Закаленный жадный жетон - Чем отличается размещение точки перед негативным взглядом

<table((?!</table>).)*</table>

соответствует всем моим тегам таблицы, однако,

<table(.(?!</table>))*</table>

не. Второй вариант, кажется, имеет смысл, если я пытаюсь записать выражение словами, но я не могу понять смысл первого.

Может кто-нибудь объяснить мне разницу?

Для справки я получил термин "Закаленный жадный жетон" здесь: http://www.rexegg.com/regex-quantifiers.html

3 ответа

Решение

Так как Google возвращает этот ТАК вопрос поверх результатов для tempered greedy token Я чувствую себя обязанным дать более полный ответ.

Что такое закаленный жадный жетон?

Ссылка на жадный токен rexegg.com довольно лаконична:

В (?:(?!{END}).)*, * квантификатор применяется к точке, но теперь это закаленная точка. Негативный взгляд (?!{END}) утверждает, что то, что следует за текущей позицией, не является строкой {END}, Поэтому точка никогда не может совпадать с открывающей скобкой {END} гарантируя, что мы не будем перепрыгивать {END} разделитель.

Вот и все: закаленный жадный токен - это своего рода класс отрицанных символов для последовательности символов (см. Класс отрицанных символов для одного символа).

ПРИМЕЧАНИЕ. Разница между закаленным жадным токеном и классом отрицанных символов заключается в том, что первый действительно не соответствует тексту, кроме самой последовательности, а является единственным символом, который не запускает эту последовательность. Т.е. (?:(?!abc|xyz).)+ не будет соответствовать def в defabc, но будет соответствовать def а также bc, так как a начинается запрещено abc последовательность и bc не.

Это состоит из:

  • (?:...)* - количественная группа без захвата (это может быть группа захвата, но нет смысла захватывать каждого отдельного персонажа) (* может быть +, зависит от того, ожидается ли совпадение пустой строки)
  • (?!...) - негативный прогноз, который фактически накладывает ограничение на значение справа от текущего местоположения
  • . - (или любой (обычно одиночный) символ) шаблон потребления.

Тем не менее, мы всегда можем дополнительно умерить токен, используя чередования в негативном прогнозе (например, (?!{(?:END|START|MID)})) или путем замены полностью совпадающей точки классом отрицанных символов (например, (?:(?!START|END|MID)[^<>]) при попытке сопоставить текст только внутри тегов).

Потребление части размещения

Заметьте, что нет упоминания о конструкции, в которой потребляющая часть (точка в исходном жадном жетоне закаленного) помещена перед смотровой площадкой. Ответ Авинаша ясно объясняет эту часть: (.(?!</table>))* сначала соответствует любому символу (кроме новой строки без модификатора DOTALL), а затем проверяет, не следует ли за ним </table> в результате чего не соответствует e в <table>table</table>, Потребляющая часть ( . ) ДОЛЖЕН быть размещен после закаливания.

Когда использовать закаленный жадный жетон?

Rexegg.com дает представление:

  • Когда мы хотим сопоставить блок текста между разделителем 1 и разделителем 2 без промежуточной строки 3 (например, {START}(?:(?!{(?:MID|RESTART)}).)*?{END}
  • Когда мы хотим сопоставить блок текста, содержащий конкретный шаблон внутри, без переполнения последующих блоков (например, вместо ленивого сопоставления точек, как в <table>.*?chair.*?</table> мы бы использовали что-то вроде <table>(?:(?!chair|</?table>).)*chair(?:(?!<table>).)*</table>).
  • Когда мы хотим сопоставить самое короткое окно из двух возможных. Ленивое соответствие не поможет, когда вам нужно получить abc 2 xyz от abc 1 abc 2 xyz (увидеть abc.*?xyz а также abc(?:(?!abc).)*?xyz).

Проблема с производительностью

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

Скажем, мы хотим соответствовать abc 2 xyz в ABC 1 ABC 2 XYZ 3 XYZ. Вместо проверки каждого символа между abc а также xyz с abc(?:(?!abc|xyz).)*xyz мы можем пропустить все символы, которые не являются a или же x с [^ax]*, а затем сопоставить все a которые не сопровождаются bca(?!bc)) и все x которые не сопровождаются yzx(?!yz)): abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz,

((?!</table>).)* будет проверять, что этот конкретный символ будет соответствовать не должен быть начальным символом в строке </table>, Если да, то только это соответствует этому конкретному символу. * повторяет один и тот же ноль или более раз.

(.(?!</table>))* соответствует любому символу, только если за ним не следует </table>ноль или более раз. Так что это будет соответствовать всем символам внутри тега таблицы, исключая последний символ, так как за последним символом следует </table>, И следующая картина </table> утверждает, что в конце совпадения должен быть тег закрывающей таблицы. Это делает матч провалиться.

Смотрите здесь

Закаленный жадный жетон действительно означает:

"матч, но только до определенного момента"

как ты это делаешь:

вы ставите токен, который вы не хотите сопоставлять, как отрицательный взгляд (?!notAllowedToMatch) перед точкой . (сопоставить что-либо одно), затем вы повторяете все это со звездой *:

((?!notAllowedToMatch).)*

как это устроено:

"Смотри и ешь один" снова и снова, перемещая один символ за раз слева направо по входной строке, пока не будет видна запрещенная последовательность (или конец строки), и в этот момент совпадение прекращается.

Более подробный ответ Виктора хорош, я просто подумал, что нужно более простое объяснение.

Другие вопросы по тегам