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

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

Страниц: 1 [2] 3 4 ... 8   Вниз
  Печать  
Автор Тема: Как заменить неизвестное заранее число вхождений в QRegExp ?  (Прочитано 53660 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Июнь 07, 2016, 14:58 »

С чего это? Никакого "завершающего" (</span>) там уже не будет. Внимательно смотрим код.
Давайте посмотрим
Код
C++ (Qt)
template <class FormatFunc>
QString regex_replace(const QString & input, const QRegExp & regex, FormatFunc format_func)
{
   QString out = input;
   int pos = 0;
   while ((pos = regex.indexIn(out, pos)) != -1)
   {
       auto s = format_func(regex.cap(1));
       out.replace( pos, regex.matchedLength(), s );
pos += s.length();
   }
   return out;
}
В момент out.replace: pos стоит на первом пробеле для замены (в строке out). Потом Вы добавляете длину строки-замены, в итоге pos стоит на начале хвостика </span>. Что не так?

Адище какое Улыбающийся
Находим через регексп текст внутри спана. Только В НАЙДЕННОМ ДИАПАЗОНЕ заменяем пробелы. Повторяем поиск с позиции конца заменененного диапазона.
Профит.
С "идеологией" никто не спорит Улыбающийся Вот только как это технически исполнить?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #16 : Июнь 07, 2016, 15:07 »

QRegExp::indexIn - дает нам начало текста.
QRegExp::matchedLength() - дает нам длину текста.
Полученный текст подвергаем replace, и вставляем его в оригинал.
Зная, на сколько поменялась длина нового текста, сдвигаем оффсет регэкспа и повторяем поиск.
Код писать влом, но по моему, задача примитивная Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #17 : Июнь 07, 2016, 15:20 »

Потом Вы добавляете длину строки-замены, в итоге pos стоит на начале хвостика </span>. Что не так?
QRegExp::matchedLength() даёт длину всего вхождения, т.е. <span>....</span>, поэтому после замены этого вхождения в out уже не будет.
Записан

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

Сообщений: 2094



Просмотр профиля
« Ответ #18 : Июнь 07, 2016, 16:17 »

Адище какое Улыбающийся
Находим через регексп текст внутри спана. Только В НАЙДЕННОМ ДИАПАЗОНЕ заменяем пробелы. Повторяем поиск с позиции конца заменененного диапазона.
Профит.
Вы тоже реплэйсом их заменять предлагаете?)  

Кстатии:
Эх, напишу-ка я файнд-реплейс Улыбающийся
Код
C++ (Qt)
...
QString ReplaceBlanks( const QString & src )
{
QString dst;
const QString & spaceTxt("&#38;#65533;");
int srcPos = 0;
TVec vec = CollectPairs(src, "<span", "</span>");
for (int i = 0; i < vec.size(); ++i) {
int beg = vec[i].first;
int end = vec[i].second;
dst += QStringRef(&src, srcPos, beg - srcPos);
for (int j = beg; j < end; ++j)
dst += spaceTxt;
srcPos = end;
}
 
dst += QStringRef(&src, srcPos, src.size() - srcPos);
return dst;
}
...
 
У Вас ведь тоже dst копируется постоянно:
Код
C++ (Qt)
dst += QStringRef(&src, srcPos, beg - srcPos);
...
dst += spaceTxt;
 
Нехорошо)
« Последнее редактирование: Июнь 07, 2016, 16:22 от m_ax » Записан

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

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #19 : Июнь 07, 2016, 16:46 »

Адище какое Улыбающийся
Находим через регексп текст внутри спана. Только В НАЙДЕННОМ ДИАПАЗОНЕ заменяем пробелы. Повторяем поиск с позиции конца заменененного диапазона.
Профит.

Вы тоже реплэйсом их заменять предлагаете?) 

Думаю, в контексте данной задачи это непринципиально.
Против реплейса я в общем ничего не имею, если это не вредит производительности и пониманию.
Вырезать строку - подменить пробелы - засунуть строку взад, как по мне, будет быстрее, чем по всему тексту шарить.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #20 : Июнь 07, 2016, 22:05 »

Цитировать
Думаю, в контексте данной задачи это непринципиально.
Угу, скажите это пользователям не нового железа с 512 MB ОЗУ на борту и 32-битной архитектурой, которым нужно обрабатывать файлы за 100MB)
Записан

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

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #21 : Июнь 07, 2016, 22:59 »

Цитировать
Думаю, в контексте данной задачи это непринципиально.
Угу, скажите это пользователям не нового железа с 512 MB ОЗУ на борту и 32-битной архитектурой, которым нужно обрабатывать файлы за 100MB)

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

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #22 : Июнь 07, 2016, 23:48 »

Цитировать
Думаю, в контексте данной задачи это непринципиально.
Угу, скажите это пользователям не нового железа с 512 MB ОЗУ на борту и 32-битной архитектурой, которым нужно обрабатывать файлы за 100MB)

Ну, это уже больше вопрос имплементации конкретного реплейса, а не алгоритма в целом.
В принципе реплейс - довольно примитивная процедура с точки зрения реализации и может быть неплохо оптимизирована.
Так,.. и каие альтернативы реализации replace Вы видете? Хотя бы концептуально, в общем?
Записан

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

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #23 : Июнь 08, 2016, 01:23 »

Допустим, исходные данные у нас имеют длину L байт, заменяемый элемент S байт, целевой - R байт.
Тогда максимум памяти, необходимой для результата, составит (L / S) * R.
Далее, (подразумеваем тупой вариант - посимвольное сравнение и замену, без всяких там регистров и перекодировок), достаточно просканировать исходные данные на вхожения заменяемых элементов и побайтово скопировать их в результирующий массив. Т.е. найдено совпадение - пишем замененное значение в результат, не найдено - пишем исходный байт и переходим к следующему и т.д.
Не знаю, что еще тут можно придумать, т.к. задача действительно тривиальная и требует только одного прохода по исходному массиву.
Быстродействие в итоге зависит от реализации сравнения паттернов, но тут тоже задача "в лоб".
Не думаю, что "слабые машины" не потянут такое Улыбающийся


 
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Июнь 08, 2016, 07:08 »

QRegExp::matchedLength() даёт длину всего вхождения, т.е. <span>....</span>, поэтому после замены этого вхождения в out уже не будет.
Так ведь задача была менять не весь блок <span>....</span>, а только пробелы в нем. Ладно, не суть, но обратите внимание: я все время путаюсь в том "коротком и простом" (дальше некуда) что Вы написали Улыбающийся И мои слабые способности - не единственное тому объяснение  Улыбающийся

У Вас ведь тоже dst копируется постоянно:
Нет, в большинстве случаев срабатывает пул QString и никаких выделений памяти не происходит. А вот предрассчитывать нужный размер ценой создания QStringList - явный перебор

Так,.. и каие альтернативы реализации replace Вы видете? Хотя бы концептуально, в общем?
Ну чего уж останавливаться на полуслове? Продолжайте, типа "а вот boost::xxx умные люди давно уже все написали!!!". Может и так, но выворачиваться наизнанку с гребаными функторами и операторами как-то не хочется. "Концептуальность" не имеет ничего общего с заучиванием очередного кусочка готового. Вероятно Вы использовали это слово по ошибке (в дусте часто встречается "concept")   
Записан
poru
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #25 : Июнь 08, 2016, 10:35 »

Обрабатывать нужно именно регулярными выражениями. Потому что, например, парсинг в DOM (с последующим обратным преобразованием) не сделает текстовую ноду из одних пробелов внутри ноды span.
Вот ключевая фраза всей темы. Дезинформация. Спецификация DOM не запрещает использовать пробелы (и только пробелы) в текстовых нодах. Обработка пробелов возлагается на пользователя, на его усмотрение.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #26 : Июнь 08, 2016, 11:34 »

Допустим, исходные данные у нас имеют длину L байт, заменяемый элемент S байт, целевой - R байт.
Тогда максимум памяти, необходимой для результата, составит (L / S) * R.
Далее, (подразумеваем тупой вариант - посимвольное сравнение и замену, без всяких там регистров и перекодировок), достаточно просканировать исходные данные на вхожения заменяемых элементов и побайтово скопировать их в результирующий массив. Т.е. найдено совпадение - пишем замененное значение в результат, не найдено - пишем исходный байт и переходим к следующему и т.д.
Не знаю, что еще тут можно придумать, т.к. задача действительно тривиальная и требует только одного прохода по исходному массиву.
Быстродействие в итоге зависит от реализации сравнения паттернов, но тут тоже задача "в лоб".
Не думаю, что "слабые машины" не потянут такое Улыбающийся
Так я к тому, что если результирующий массив (его size) окажется больше изначального размера capacity, придётся аллоцировать под него новый кусок памяти,  ну и + скопировать из старого в новый. При частом вызове такого реплайсе это может привести к фрагментации памяти (особено на старом железе).

Цитировать
А вот предрассчитывать нужный размер ценой создания QStringList - явный перебор
А там QStringList не только для этого нужен. Я же писал, что это даёт мне возможность "на лету" в лямбде обрабатывать более сложные условия/случаи. Вам же для этого придётся писать новые функции..

Цитировать
Ну чего уж останавливаться на полуслове? Продолжайте, типа "а вот boost::xxx умные люди давно уже все написали!!!".
А что в этом плохого? Да, буст это инструмент, гибкий и отлично продуманный. Там можно подсмотреть не мало концептов и решений. И понимание и изучение их гораздо более полезнее для собственного развития, чем написания велосипедов в стиле C с классами. )
 
« Последнее редактирование: Июнь 08, 2016, 11:36 от m_ax » Записан

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

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #27 : Июнь 08, 2016, 11:41 »

Так я к тому, что если результирующий массив (его size) окажется больше изначального размера capacity, придётся аллоцировать под него новый кусок памяти,  ну и + скопировать из старого в новый. При частом вызове такого реплайсе это может привести к фрагментации памяти (особено на старом железе).

Реаллокаций памяти тут в любом случае не избежать. Можно сделать более "хитро" и сначала подсчитать количество всех заменяемых объектов, аллоцировать память за один раз и вторым проходом выполнить замену - но тогда придётся расплачиваться быстродействием. Ну или же сразу выделить огромный буфер, заведомо покрываюший все нужны - но тогда платим памятью Улыбающийся

Цитировать
А там QStringList не только для этого нужен. Я же писал, что это даёт мне возможность "на лету" в лямбде обрабатывать более сложные условия/случаи. Вам же для этого придётся писать новые функции..

"Лямбда" - это по сути тоже функия Улыбающийся И Вам придется писать новые лямбды, от этого тоже никуда)

Цитировать
Да, буст это инструмент, гибкий и отлично продуманный.  

Насчет последних двух утверждений - я бы поспорил Улыбающийся
Но поскольку это форум по Qt, наверняка народ ожидает решений в стиле Qt...
« Последнее редактирование: Июнь 08, 2016, 11:42 от Racheengel » Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #28 : Июнь 08, 2016, 11:56 »

Цитировать
"Лямбда" - это по сути тоже функия  Улыбающийся И Вам придется писать новые лямбды, от этого тоже никуда)
Конечно, только лямбду пишет сам пользователь "на лету" в зависимости от его конкретной задачи. Как правило это будет лёгковесное изменение. Ему не нужно для этого писать заново всю regexp_replace. Улыбающийся Тем самым с одной функцией он может решать разные задачи.

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



Записан

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

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


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

Вот, предположим, я поверил в непогрешимость буста Улыбающийся И начал прикручивать regex_replace.
Ок, идем в доку (сюды http://www.boost.org/doc/libs/1_61_0/doc/html/boost/xpressive/regex_replace.html), смотрим...

template<typename OutIter, typename BidiIter, typename Formatter>
  OutIter regex_replace(OutIter out, BidiIter begin, BidiIter end,
                        basic_regex< BidiIter > const & re,
                        Formatter const & format,
                        regex_constants::match_flag_type flags = regex_constants::match_default,
                        unspecified = 0);

Ну ок, итераторы там (хотя на что? что есть входными и выходными параметрами для них? какой тип данных? какие контейнеры? Надо ли мне иметь уже преалоцированный контейнер для результатов или оно "само сделается"?)

Ладно, нашел вариант, который использует Char* str как инпут... Но вопрос, а где тогда output?? Ни примеров, ни описания...

Дальше,  basic_regex - по идее, тут я должен прописать свой РыгЭксп... Упираемся в такое: http://www.boost.org/doc/libs/1_61_0/doc/html/boost/xpressive/basic_regex.html

template<typename InputIter>
  static basic_regex< BidiIter >
  compile(InputIter begin, InputIter end,
          flag_type flags = regex_constants::ECMAScript);

Ок, рыгэксп надо задавать какими-то биде-итераторами... Ни примеров, ни-че-го Грустный

Идем дальше, нужен  Formatter const & format, который, судя по мелкому примечанию внизу, будет вызван после каждого поиска:

Otherwise, for each match found, if !(flags & format_no_copy) calls std::copy(m.prefix().first, m.prefix().second, out), and then calls m.format(out, format, flags).

То есть, оно таки берет и тупо копирует кусок памяти (с аллокациями и т.д.), а потом вызывает форматтер... Приехали к тому, что обсуждалось выше Грустный
 
Самое веселое - API данного форматера я так и не увидел, покажите...?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: 1 [2] 3 4 ... 8   Вверх
  Печать  
 
Перейти в:  


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