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

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

Страниц: [1] 2 3 ... 7   Вниз
  Печать  
Автор Тема: Разбор QString  (Прочитано 62900 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июнь 28, 2012, 18:11 »

Добрый день

Навеяно этим http://www.prog.org.ru/index.php?topic=22314.msg156566#msg156566. Как всегда, тыкается в нос могучий RegExp но в конце-концов выясняется что почему-то не работает  Плачущий Накидал простенький класс (аттач) который ни на что не претендует, просто разбирается с кавычками, скобками. Предоставляется "as is"

Краткое описание
Код
C++ (Qt)
// заряжаем параметры разбора
QString delims(" \t");   // 2 символа-разделителя (пробел и табуляция)
QString tokens(",:");   // 2 символа-токена (запятая и двоеточие)
CParseParam param(delims, tokens);
 
// определяем что будет в качестве "цитат" (quote)
param.AddQuote(100, "{", "}");
param.AddQuote(100, "'");
param.AddQuote(0, "\\\"");
param.AddQuote(0, "\"");
 
Пояснения:

1) Символы-разделители - с ними все ясно

2) Символы-токены - то же что и разделители но с той разницей что и сами выдаются в результат. Простой пример запятая
Цитировать
1,3
Определив запятую как символ-разделитель мы получим на выходе 2 строки (1 и 3) и не можем контролировать какой был разделитель, сколько было запятых (одна или больше). Выгоднее иметь запятую как символ-токен

3) Quotes - блокируют символы-разделители и символы-токены. Все внутри quotes, выдается как 1 строка. Quotes имеют приоритет (0 - наивысший). Напр скобки не воспринимаются как quotes если они внутри двойных кавычек приоритет которых выше. Наоборот, кавычки внутри скобок воспринимаются и должны быть сначала закрыты кавычки, а потом скобки.  Quotes c одинаковым приоритетом разбираются в порядке LIFO, напр
Цитировать
"abc de \"fgh" ik
Кавычка после h не закрывает quote - ожидается вложенная кавычка \"

4) Ну и собственно использование
Код
C++ (Qt)
QString str("1, { 2 }, 3");
QStringRef ref;
QStringParser parser(str, param);
while (parser.NextToken(ref))
qDebug() << ref.toString();
 
Любое кол-во парсеров может использовать один и тот же блок параметров разбора. Результат выдается в виде QStringRef (т.е. мы всегда знаем в каком месте исходной строки находимся). Лучше не спешить переводить в QString, а напр можно начать разбор вложенного
Код
C++ (Qt)
if (param.RemoveQuote(ref)) {
QStringRef ref2;
QStringParser parser2(ref, param);
while (parser2.NextToken(ref2))
 ...
}
 


Это все, спасибо за внимание

Edit: последняя версия от 30 июня
« Последнее редактирование: Июнь 30, 2012, 01:57 от Igors » Записан
alexis031182
Гость
« Ответ #1 : Июнь 28, 2012, 18:29 »

Нужная вещь, спасибо. Интересно ещё, если сравнить скорость выполнения с регуляркой на одинаковых шаблонах.
Записан
alexis031182
Гость
« Ответ #2 : Июнь 28, 2012, 19:22 »

Таки разница есть и весьма существенная...

Этот код
Код
C++ (Qt)
QString src="1,2,3,{4,5,6},7,8,9";
QRegExp rx("([^,]|\\{.*\\})");
 
for(int i = 0; i < 1000000; ++i) {
   int pos = 0;
   while((pos = src.indexOf(rx,pos))>=0) {
       pos+=rx.cap(0).length();
   }
}
 
выполнился на моей машине за
real   0m4.570s
user   0m4.520s
sys   0m0.004s

и

real   0m4.563s
user   0m4.548s
sys   0m0.000s

Альтернативный вариант Igors
Код
C++ (Qt)
QString temp, src="1,2,3,{4,5,6},7,8,9";
CParseParam param;
param.AddDelim(",");
param.AddQuote(100, "{", "}");
 
for(int i = 0; i < 1000000; ++i) {
   QStringParser parser(src, param);
   while(parser.NextToken(temp)) {}
}
 
за
real   0m0.939s
user   0m0.928s
sys   0m0.004s

и

real   0m0.928s
user   0m0.920s
sys   0m0.004s
Записан
alexis031182
Гость
« Ответ #3 : Июнь 28, 2012, 19:27 »

Единственное, компилятор предупреждение выдал, что параметры mStr и mParam класса QStringParser инициализируются в конструкторе не в том порядке, в котором объявлены. Честно говоря, впервые такое сообщение наблюдаю. Но может от того, что всегда получалось порядок соблюдать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июнь 29, 2012, 09:27 »

Почистил, изменения 29 июня

1) Убрал warning компилятора

2) Исправлена ошибка в приоритетах

3) В метод NextToken добавлен параметр stopOnQuoteEnd - возможность извлекать по quote. Пример
Цитировать
{ 1 }{ 2 }
Это "не делится", т.к. нет разделителя между }{. Установив stopOnQuoteEnd мы поделим

4) Добавлены утилитарные методы
CParseParam::QuoteStart - определить что строка начинается с quote
CParseParam::RemoveQuite - убрать bounding quotes (т.е. подготовить суб-строку для разбора)
QStringParser::GetCurDelim - посмотреть на каком разделителе стоим

Таки разница есть и весьма существенная...
А как (каким тулзом) Вы так лихо меряете?
Записан
alexis031182
Гость
« Ответ #5 : Июнь 29, 2012, 09:49 »

А как (каким тулзом) Вы так лихо меряете?
Линуксовой консольной командой time
Записан
trot
Гость
« Ответ #6 : Июнь 29, 2012, 10:17 »

Выступлю в защиту регулярных выражений.
Во-первых, выражение
Цитировать
QRegExp rx("([^,]|\\{.*\\})");
является "жадным", а значит, с точки зрения быстродействия, достаточно неэффективное.
Если мы боремся за быстродействие, то это выражение нужно переписывать, т.е. избавляться от конструкции .* .
Во-вторых, предложенный вариант Igors решает узконаправленную задачу, и в этом случае да возможно вы добьетесь лучшего быстродействия.
В-третьих, регулярные выражение досточно универсальный и мощный инструмент (если умело им пользоваться) который имеет под собой теоритические основы.
В четвертых, практика показывает, что к этому инструменту редко обращаются, а отсюда вытекают все проблемы (теряется навык, забывается синтаксис и т.д.). Кроме этого пользователь не может четко сформулировать, то что ему надо иметь на выходе и какие варианты исходных данных могут быть. Чаще всего к решению подходят с кандока.
В пятых, не понимаю зачем заново придумывать велосипед. С таким подходом можно отказаться от всех инструментов, которые есть и делать свое, но на это не хватит ни сил ни времени.
Записан
Bepec
Гость
« Ответ #7 : Июнь 29, 2012, 10:24 »

Регулярные выражения - как двухметровый нож для хлеба Веселый

Нужны - редко.
Зачастую нужно просто скобочки разбить, да надёргать значений.
Возможностей дофига, но зачастую обычно они не нужны.
Медленные - да. Изза количества возможностей Улыбающийся
И забываются быстро :/ Я вот уже с трудом напишу регексп средненький.

То есть - хороший, прекрасно заточенный, тяжеленный, гибкий, двухметровый нож для хлеба Веселый

Вот ток зачастую нужен карманный 5 см Улыбающийся
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Июнь 29, 2012, 10:28 »

Регулярки универсальны, в этом их плюс.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
DmitryM
Гость
« Ответ #9 : Июнь 29, 2012, 10:48 »

Медленные - да. Изза количества возможностей Улыбающийся
Обычно регекспы реализуются конечными автоматами, которые хорошо оптимизированы, поэтому может получиться так, что регекспы работают быстрее самописного парсера.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #10 : Июнь 29, 2012, 10:55 »

А как (каким тулзом) Вы так лихо меряете?
Отвечу за alexis031182 - time )
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июнь 29, 2012, 11:35 »

Отвечу за alexis031182 - time )
Я так и знал - это надо что-то набирать в Terminal, для меня это мучение  Плачущий Плачущий

В пятых, не понимаю зачем заново придумывать велосипед. С таким подходом можно отказаться от всех инструментов, которые есть и делать свое, но на это не хватит ни сил ни времени.
А разве я против изучить RegExp чтобы потом его применять? Да, выражения выглядят ужасно, но если "надо - так надо". Однако мой энтузиазм охлаждает вот эта фраза из букваря
Цитировать
Note that in general regexps cannot be used to check for balanced brackets or tags.
А у меня этих balanced полным-полно. Чего же я буду изучать и приспосабливать то что для моих целей не предназначено? Да еще хз удастся ли приспособить...

Во-вторых, приведенная в посте #1 ссылка - далеко не единственный пример, где по каким-то причинам RegExp не достигает результата - даже в умелых руках. Получается "изучить и применить" в данном случае совсем не так дешево как хотелось.

В-третьих, поправьте если не так, но я не наблюдаю в RegExp последовательного разбора, т.е. сначала мне нужно расфасовать все по суб-строкам, потом уже заниматься каждой/деталями. Это страшный невдобняк

Ну и чисто "человеческий фактор". Очень может быть что "самописный" вариант коряв и где-то уже есть намного лучший (хотя впрочем необязательно Улыбающийся). Однако свой текст я прекрасно понимаю, а вот юзая готовый - не очень, фактически запоминается вход-выход, типа "дадим это - получим то-то". Хмм... не вызывает ли это смутное чувство неудовлетворенности, и не потому ли так активно охаивают велосипедистов?  Улыбающийся

Ладно, завтра будет время - заточу по скорости, а то там в парсере все же зовется malloc - нехорошо
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #12 : Июнь 29, 2012, 12:56 »

Ладно, завтра будет время - заточу по скорости, а то там в парсере все же зовется malloc - нехорошо

Igors, в коде от 29 числа я ненашел вызова malloc (хотелось бы увидеть контекст использования), поэтому задам более общий вопрос. Чем навеяно то, что malloc медленная функия? Или имелось ввиду что-то дргое?
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Июнь 29, 2012, 13:19 »

Igors, в коде от 29 числа я ненашел вызова malloc (хотелось бы увидеть контекст использования), поэтому задам более общий вопрос. Чем навеяно то, что malloc медленная функия? Или имелось ввиду что-то дргое?
Неявно, mStack.push_back его все-таки вызовет. "Медленная" - ну смотря к чему мерять. В данном случае остальной код соразмерим с вызовом malloc, поэтому убрать его есть смысл.
Записан
DmitryM
Гость
« Ответ #14 : Июнь 29, 2012, 13:31 »

Неявно, mStack.push_back его все-таки вызовет. "Медленная" - ну смотря к чему мерять.
Только push_back не всегда вызывает malloc
Записан
Страниц: [1] 2 3 ... 7   Вверх
  Печать  
 
Перейти в:  


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