Russian Qt Forum
Ноябрь 23, 2024, 06:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Сохранить вложенную "константу строки" в RegExp  (Прочитано 11199 раз)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« : Август 20, 2019, 12:54 »

Нужен разбор строки аналогичный QStringList parts = entire.split(QRegExp("\\W+"), QString::SkipEmptyParts);, но чтобы если в ней встречается последовательность символов между двойных кавычек, она целиком и без кавычек переносилась в элемент List-а. То есть, если есть строка:

Мама, глядя, сказала: "твою мать"\n и ушла.

Она разбиралась на

Мама
глядя
сказала
твою мать
и
ушла

То есть, строка эта изначально в QString (не строковая константа в коде), а \n - символ перевода каретки внутри неё. Может у кого-нибудь в коллекции есть такое? В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.
« Последнее редактирование: Август 20, 2019, 13:02 от Гурман » Записан

2^7-1 == 127, задумайтесь...
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #1 : Август 20, 2019, 14:48 »

Цитировать
В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.
Плохо искали) Помню, одно время эта тема горячо обсуждалась) И решений было несколько предложено) http://www.prog.org.ru/topic_22338_0.html

А вообще для этого есть boost::tokenizer https://www.boost.org/doc/libs/1_66_0/libs/tokenizer/  

Код
C++ (Qt)
#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
 
using namespace boost;
 
int main()
{  
   std::string s = "Мама, глядя, сказала: \"твою мать\" \\n и ушла.";
 
   escaped_list_separator<char> sep("\\", ":,", "\"");
 
   tokenizer<escaped_list_separator<char>> tok(s, sep);
 
   for(const auto & res : tok)
   {
          std::cout << res << std::endl;
   }
   return 0;
}
 

« Последнее редактирование: Август 20, 2019, 15:08 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #2 : Август 20, 2019, 22:11 »

Цитировать
В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.
Плохо искали) Помню, одно время эта тема горячо обсуждалась) И решений было несколько предложено) http://www.prog.org.ru/topic_22338_0.html

А вообще для этого есть boost::tokenizer https://www.boost.org/doc/libs/1_66_0/libs/tokenizer/  

Просмотрел, там много воды и нет явного подходящего варианта. Много лишнего, задача немного другая, немного проще - в строке цельные токены выделяются только кавычками. Ковырять и экспериментировать мне некогда. Boost и std:string не подходят, у меня их нет в приложении вообще, оно делается для Android. Сейчас пока на GNU CC, потом для выпуска перейду на Clang - там родное Qt-шное гарантированно работает, а с посторонними библиотеками и тулзами не известно. Поэтому только QString и собственные библиотеки Qt5.
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Август 21, 2019, 08:55 »

А вообще для этого есть boost::tokenizer
Пример ниже дает такой выхлоп
Цитировать
Мама
 глядя
 сказала
 твою мать
 и ушла
Т.е. он рубит по запятым. Ладно, добавил пробел во второй аргумент
Код:
escaped_list_separator<char> sep("\\", " :,", "\"");
Тогда
Цитировать
Мама

глядя

сказала

твою мать

и
ушла
Чего он насовал пустых строк?

И еще: поменял \n на \r (есть такие старые текстовики)
Код:
std::string s = "Мама, глядя, сказала: \"твою мать\" \\r и ушла";
Хирак - exception Плачущий За что?

Ну и дока, как всегда, полный отстой. Приводят пример - та покажите что он печатает - ни фига. В общем,  не все так радужно как говорят фаны дуста  Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #4 : Август 21, 2019, 12:38 »

Цитировать
В общем,  не все так радужно как говорят фаны дуста  Улыбающийся
Я уже не однократно говорил в цитируемой выше теме, что главным преимуществом tokenizer является его расширяемость.
И также, в той теме, я привёл пример, как переопределив TokenFunction (один из шаблонов tokenizerа) можно добиться любого поведения.

Я бы предложил TC, на основе архитектуры boost::tokenizer, написать свой класс QTokenizer. Думаю, это работа на пару вечеров.   
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #5 : Август 21, 2019, 15:21 »

Я бы предложил TC, на основе архитектуры boost::tokenizer, написать свой класс QTokenizer. Думаю, это работа на пару вечеров.   
Когда-нибудь в другой раз. Мне меньше чем за 10 дней до отъезда надо кучу всего сделать. Поскольку решение быстро не было найдено, пришлось изменить спецификации - разрешить в строке простые тэги и быстро сделать разбор строки по ним. За полдня. Так что вопрос пока снимается. Но вообще писание самих регэкспов достаточно муторное занятие, интересно было бы иметь что-то вроде "библиотеки" из них. Публичной, разумеется. Чтобы в ней можно было найти готовое решение для своей задачи, или хотя бы с минимальной корректировкой, возможностью тут же онлайн проверить вводом тестовой строки.

Может быть такое уже и есть, но я не нашёл.
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Август 21, 2019, 17:32 »

Я уже не однократно говорил в цитируемой выше теме, что главным преимуществом tokenizer является его расширяемость.
И также, в той теме, я привёл пример, как переопределив TokenFunction (один из шаблонов tokenizerа) можно добиться любого поведения.
Это там где имена "bra" и "ket"? (больше ничего не помню  Улыбающийся). Ну ладно, попробуем, как говорится, "конструктивно". Вот добавили пробел как символ-разделитель, и Ваш пример "почти работает", но есть бяка - пустые строки. Причем почему-то между "и" и "ушла" пустышки нет. Как от них избавиться? Ладно, еще читаем доку, глядим в исходники - ага, если больше одного разделителя, он выдает остальные "на гора" (неудобно сделано). Причем для char_separator есть traits чтобы это подавить, а вот для escaped_list_separator нема  Плачущий 

А время-то идет. И как решать с пустышками - хз. Наверное придется предъявить "testimonium paupertatis" и фильтровать на выходе. Ото и вся "расширяемость" - сломалась на первом скачке. Или я неправ?

Я бы предложил TC, на основе архитектуры boost::tokenizer, написать свой класс QTokenizer. Думаю, это работа на пару вечеров.   
Если ничего больше не надо кроме "текст в кавычках" (т.е. нет скобок, вложенности, экранированных кавычек и.т.п.) - то написать с нуля, чисто на QString... ну минут 15, какие там "пару вечеров"  Улыбающийся

Ну хорошо, допустим подсчет затраченного времени = фигня (хотя я так не считаю), зато "на основе архитектуры" - это будет круто, не то что там какой-то велик (ну мы же читали/изучали, зря что ли?). И опять-таки не могу согласиться. Откройте тот же escaped_list_separator - там же ничего нет, та же студенческая лаба, только с задроченым  сынтаксысом. Это слишком бедная основа чтобы на ней что-то развивать.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #7 : Август 21, 2019, 19:23 »

Код:
(?<=").+(?=")|\b\w+\b

проверил на свифте:
Код:
import Foundation

let p = #"(?<=").+(?=")|\b\w+\b"#
let re = try! NSRegularExpression(pattern: p, options: [])
let s = "Мама, глядя, сказала: \"твою мать\"\n и ушла."
for match in re.matches(in: s, range: NSRange(location: 0, length: s.count)) {
  print((s as NSString).substring(with: match.range))
}
вместо просмотра кавычек вперед/назад можно захватить .+
« Последнее редактирование: Август 22, 2019, 10:23 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Август 22, 2019, 05:07 »

Еще копнем boost::tokenizer, попробуем вложенные кавычки
Код:
int main()
{
    std::string s = "str1 \"str2 'str3 str4' str5\" str6";

    escaped_list_separator<char> sep("\\", " ", "\"'");

    tokenizer<escaped_list_separator<char>> tok(s, sep);

for (const auto & res : tok)
   std::cout << res << std::endl;

    return 0;
}
Выхлоп
Цитировать
str1
str2 str3
str4 str5
str6
И опять проблемы, и опять как их решать - хз.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #9 : Август 22, 2019, 11:29 »

Цитировать
И опять проблемы, и опять как их решать - хз.
Да, escaped_list_separator, возможно, представляет не самое продуманное решение.
Но что мешает дополнить tokenizer своим spec_char_separator'ом? Который будет и множественные и вложенные цитаты учитывать,
и токены различные и т.д. и т.п.
При этом в той теме (Разбор QString) я уже выкладывал такое решение. Выложу ещё раз)
Код
C++ (Qt)
#include <iostream>
#include <boost/tokenizer.hpp>
#include "spec_token_functions.h"
 
int main()
{
   std::string str = "str1 \"str2 'str3 str4' str5\" str6";
 
   quote_list<char> quotes('\'', '\'');
   quotes.add_quote('"', '"');
 
   std::string dropped_delims = " ";
   std::string kept_delims = "";
 
   boost::tokenizer<spec_char_separator<char>> tok(str, spec_char_separator<char>(dropped_delims, kept_delims, quotes));
 
   for (auto s : tok)
       std::cout << s << std::endl;
 
   return 0;
}
 
 

Вывод:
Код
Bash
str1
"str2 'str3 str4' str5"
str6
 

Приаттачиваю проектик.
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Август 22, 2019, 14:41 »

При этом в той теме (Разбор QString) я уже выкладывал такое решение. Выложу ещё раз)
...
Приаттачиваю проектик.
За проект спасибо, разрывать старье было бы чижело. Однако проект - вовсе не main что Вы процитировали - содержательная часть там в хедере, строк 240 - не так уж мало, и код не так уж очевиден. 

Тогда возникает законный вопрос - а что это за инструментарий такой (tokenizer) если для достижения даже относительно простого ф-ционала уже нужно наклепать не одну сотню строк? Ведь решение "с нуля" отнюдь не длиннее. Заметим что если наращивать ф-ционал - то опять все руками, напр
Цитировать
std::string str = "str1 'str2 \"str3' str4\" str5' str6";
Это сейчас не работает, нет приоритета кавычек. Потребуется добавить - опять все на Вас. Тогда зачем брать tokenizer за основу? Что Вы с него имеете? Концепцию токенов? Ну QStringRef в этом плане никак не хуже. Что еще? Навязанный call оператор ()? Так это в минус.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #11 : Август 22, 2019, 14:56 »

Цитировать
содержательная часть там в хедере, строк 240 - не так уж мало, и код не так уж очевиден.
Ну не 240 строк.. Последний класс quote_extractor (Вот Вам другой пример поведения токенайзера, когда токены - это содержимое цитат) не нужен для Вашего примера.
Вся содержательная часть содержится как раз в теле оператора operator()() где меньше 50 строк кода.

Цитировать
Тогда возникает законный вопрос - а что это за инструментарий такой (tokenizer) если для достижения даже относительно простого ф-ционала уже нужно наклепать не одну сотню строк?

В расширяемости, без изменения его интерфейса. Вы можете написать множество (для разных узких специализаций) вариантов разбиения на токены.
И это архитектурно правильный подход, чем писать на каждый случай новый парсер. Мы же об этом уже 100500 раз спорили в той теме)

Цитировать
Это сейчас не работает, нет приоритета кавычек.
Приоритет кавычек - это вообще отдельная песня.. Мы это тоже обсуждали, если помните) И что я об этом думаю, можете также найти в известной теме))



 
« Последнее редактирование: Август 22, 2019, 15:12 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Август 23, 2019, 03:59 »

Вся содержательная часть содержится как раз в теле оператора operator()() где меньше 50 строк кода.
Ну если вызываемые утилиты не считать..  Улыбающийся

В расширяемости, без изменения его интерфейса. Вы можете написать множество (для разных узких специализаций) вариантов разбиения на токены.
И это архитектурно правильный подход, чем писать на каждый случай новый парсер. Мы же об этом уже 100500 раз спорили в той теме)
В том что "растительное масло без холестерина" никакой дустовской заслуги нет Улыбающийся Возобновлять старый спор нет смысла т.к. рез-т давно известен Улыбающийся Поговорим о другом

А вообще: нужно ли "множество вариантов разбиения на токены"?  Вот популярная хотелка
Цитировать
21.32
2.12e+4
2.1e-5f
Как получить токен-флот? Можно просто забить на точку, плюс и минус и попробовать конвертнуть строку - пройдет или нет. Но тогда лишаемся такой возможности
Цитировать
2+2
Наверное лучше все-таки плюс ловить. Тогда что - менять нутро "разбивщика"? Добавлять ему еще опции? Но это никакая не "расширяемость"

Думается правильно сделать еще класс (layer) который принимает "сырые" токены базового, и как-то их группирует 
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #13 : Август 23, 2019, 11:38 »

Цитировать
Вот популярная хотелка
...
Как получить токен-флот? Можно просто забить на точку, плюс и минус и попробовать конвертнуть строку - пройдет или нет. Но тогда лишаемся такой возможности
Да чтож это за мания у Вас такая: из всего своять супер класс)
Умеете утюг - замечательно, но будет немного дико с его помощью решать все проблемы Улыбающийся

Токенайзер решает узкий круг специальных задач. Он расширяем, производителен и простой. Всё.

Хотите большего, ищите соответствующий инструментарий. 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #14 : Август 24, 2019, 14:33 »

тогда лишаемся такой возможности
Цитировать
2+2
Эта хотелка давно и просто делается рекурсивным разбором выражений. Описано в любом учебнике по компиляторам. Можно просто тупо брать ветку БНФ из языка Си, и реализовывать. Разумеется, таким же разбором можно и кавычки и любые скобки разбирать без всяких RegExp, но в реальном приложении это будет стрельба из пушки по воробьям.
Записан

2^7-1 == 127, задумайтесь...
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.147 секунд. Запросов: 23.