Russian Qt Forum

Qt => Общие вопросы => Тема начата: Гурман от Август 20, 2019, 12:54



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

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

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

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

То есть, строка эта изначально в QString (не строковая константа в коде), а \n - символ перевода каретки внутри неё. Может у кого-нибудь в коллекции есть такое? В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 20, 2019, 14:48
Цитировать
В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.
Плохо искали) Помню, одно время эта тема горячо обсуждалась) И решений было несколько предложено) http://www.prog.org.ru/topic_22338_0.html (http://www.prog.org.ru/topic_22338_0.html)

А вообще для этого есть boost::tokenizer https://www.boost.org/doc/libs/1_66_0/libs/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;
}
 



Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Гурман от Август 20, 2019, 22:11
Цитировать
В кладовой готовых я не нашёл, гугл выдаёт всякую хрень.
Плохо искали) Помню, одно время эта тема горячо обсуждалась) И решений было несколько предложено) http://www.prog.org.ru/topic_22338_0.html (http://www.prog.org.ru/topic_22338_0.html)

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

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


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

глядя

сказала

твою мать

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

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

Ну и дока, как всегда, полный отстой. Приводят пример - та покажите что он печатает - ни фига. В общем,  не все так радужно как говорят фаны дуста  :)


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 21, 2019, 12:38
Цитировать
В общем,  не все так радужно как говорят фаны дуста  :)
Я уже не однократно говорил в цитируемой выше теме, что главным преимуществом tokenizer является его расширяемость.
И также, в той теме, я привёл пример, как переопределив TokenFunction (один из шаблонов tokenizerа) можно добиться любого поведения.

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


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

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


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 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 - там же ничего нет, та же студенческая лаба, только с задроченым  сынтаксысом. Это слишком бедная основа чтобы на ней что-то развивать.


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: kambala от Август 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))
}
вместо просмотра кавычек вперед/назад можно захватить .+


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 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
И опять проблемы, и опять как их решать - хз.


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 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
 

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


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 22, 2019, 14:41
При этом в той теме (Разбор QString) я уже выкладывал такое решение. Выложу ещё раз)
...
Приаттачиваю проектик.
За проект спасибо, разрывать старье было бы чижело. Однако проект - вовсе не main что Вы процитировали - содержательная часть там в хедере, строк 240 - не так уж мало, и код не так уж очевиден. 

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


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 22, 2019, 14:56
Цитировать
содержательная часть там в хедере, строк 240 - не так уж мало, и код не так уж очевиден.
Ну не 240 строк.. Последний класс quote_extractor (Вот Вам другой пример поведения токенайзера, когда токены - это содержимое цитат) не нужен для Вашего примера.
Вся содержательная часть содержится как раз в теле оператора operator()() где меньше 50 строк кода.

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

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

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



 


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 23, 2019, 03:59
Вся содержательная часть содержится как раз в теле оператора operator()() где меньше 50 строк кода.
Ну если вызываемые утилиты не считать..  :)

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

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

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


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 23, 2019, 11:38
Цитировать
Вот популярная хотелка
...
Как получить токен-флот? Можно просто забить на точку, плюс и минус и попробовать конвертнуть строку - пройдет или нет. Но тогда лишаемся такой возможности
Да чтож это за мания у Вас такая: из всего своять супер класс)
Умеете утюг - замечательно, но будет немного дико с его помощью решать все проблемы :)

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

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


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


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 24, 2019, 15:00
Он расширяем, производителен ...
Философия (дустовского) сачка не заслуживает обсуждения  :)

Цитировать
double test = 1.3e+2+5;
Это свинство компилится, test = 135. Хммм... как же его цивильно (без хардкодинга) распарсить ?


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: m_ax от Август 24, 2019, 16:41
Я не понял, это Вы к чему?)


Название: Re: Сохранить вложенную "константу строки" в RegExp
Отправлено: Igors от Август 25, 2019, 10:05
Я не понял, это Вы к чему?)
Ну обдумываю как "я бы делал" парсер арифметики/интерпретатора. Это не значит что мне он "срочно нужен" (пока вообще не нужен). Но если понадобится - там уже думать/обсуждать будет некогда, придется чего-то искать/хватать. В общем, "на будущее".