Лучше использовать некожадный классификатор или упущение?
У меня есть, возможно, большой блок текста для поиска экземпляров [[...]]
, где ...
может быть чем угодно, включая другие скобки (хотя они не могут быть вложенными; первый экземпляр ]]
после [[
заканчивается матч).
Я могу придумать два способа сопоставить этот текст:
- Использование не жадного квалификатора:
/\[\[.+?\]\]/
- Используя взгляд в будущее:
/\[\[(?:(?!\]\]).)+\]\]/
Является ли один выбор по своей сути лучшим, чем другой, с точки зрения производительности (я бы сказал, что первый, вероятно, более читабелен)? Я помню, что читал, что лучше не использовать не жадные квалификаторы, но я не могу сейчас найти источник для этого.
4 ответа
В этом случае лучше использовать не жадный квантификатор.
Возьми этот пример строки "[[a]b]]"
Нежадный квантификатор
\[\[.+?\]\] Атом # 1 2 3 4 5
- Атом № 1
\[
Матчи - Атом № 2
\[
Матчи - Атом № 3
.+?
соответствует"a"
- Атом № 4
\]
Матчи - Атом № 5
\]
не может вернуться к #3, но сохранить позицию строки - Атом № 3
.+?
соответствует"]"
- Атом № 4
\]
не может вернуться к #3, но сохранить позицию строки - Атом № 3
.+?
соответствует"b"
- Атом № 4
\]
Матчи - Атом № 5
\]
Матчи - успех
Смотреть вперед:
\ [\ [(?:?! (\] \].))+\]\] Атом # 1 2 3 4 5 6 7
- Атом № 1
\[
Матчи - Атом № 2
\[
Матчи - Атом № 4
(?!\]\])
успешно (т.е. не соответствует) сразу в"a"
, продолжать - Атом № 5
.
соответствует"a"
повторите в #3 - Атом № 4
(?!\]\])
достигает частичного соответствия в"]"
- Атом № 4
(?!\]\])
успешно (т.е. не соответствует) в"b"
, продолжать - Атом № 5
.
соответствует"]"
повторите в #3 - Атом № 4
(?!\]\])
успешно (т.е. не соответствует) сразу в"b"
, продолжать - Атом № 5
.
соответствует"b"
повторите в #3 - Атом № 4
(?!\]\])
достигает частичного соответствия в"]"
- Атом № 4
(?!\]\])
достигает полного соответствия в"]"
, ergo: #4 не удалось, выход № 3 - Атом № 6
\]
Матчи - Атом № 7
\]
Матчи - успех
Таким образом, похоже, что у жадного квантификатора меньше работы.
Отказ от ответственности: это искусственный пример, и реальная производительность может отличаться в зависимости от ввода, фактического выражения и реализации механизма регулярных выражений. Я только на 98% уверен, что то, что я здесь изложил, - это то, что на самом деле происходит, поэтому я открыт для исправлений. Кроме того, как и во всех советах по производительности, не принимайте это за чистую монету, сделайте свои собственные сравнительные тесты, если хотите знать наверняка.
Другой вариант: /\[\[((?:\]?[^]])+)]]/
Он не использует ни жадных квантификаторов, ни прогнозных показателей. Это позволяет один ]
перед любым]
, Если бы было два ]
последовательно внутреннее повторение остановится, и совпадение закончится.
Этот шаблон лучше всего использовать с движками регулярных выражений для компиляции FSA. На двигателях с обратным слежением он может работать медленнее, чем не жадный вариант.
Какой вкус регулярных выражений вы используете? Если это тот, который поддерживает собственнические квантификаторы, есть намного лучшая альтернатива:
\[\[(?:[^\]]++|\](?!\]))*+\]\]
[^\]]++
поглощает любые символы, кроме ]
и не заботится о сохранении информации о состоянии, которая сделала бы возможным возврат. Если он видит ]
, он выполняет предварительный просмотр, чтобы увидеть, есть ли другой. Оборачивание всего этого в другой собственник-квантификатор означает, что он только смотрит вперед, когда видит ]
и возвращается только один раз: когда находит закрытие ]]
,
Позитивные квантификаторы поддерживаются версиями Java, JGSoft, PCRE (PHP), Oniguruma (Ruby 1.9) и Perl 5.12. Все эти ароматы также поддерживают атомарные группы, которые можно использовать для достижения того же эффекта:
\[\[(?>(?:(?>[^\]]+)|\](?!\]))*)\]\]
Разновидность.NET поддерживает атомарные группы, но не собственнические кванторы
Я думаю, что лучше использовать не жадный классификатор. Вы уверены, что в статье, которую вы прочитали, не было сказано "будьте осторожны с жадным сопоставлением?