Закаленный жадный токен – что отличает размещение точки до негативного взгляда
<table((?!).)*
соответствует всем моим табличным тегам, однако,
<table(.(?!))*
не. Второй, кажется, имеет смысл, если я пытаюсь выписать выражение в словах, но я не могу понять первое.
Может кто-нибудь объяснить мне разницу?
- Получить индекс шаблона в строке с использованием регулярного выражения
- RegEx для исключения конкретной строковой константы
- Разделение на запятую вне цитат
- Замена всех не-буквенно-цифровых символов пустыми строками
- Как выполнить частичное совпадение с java.util.regex. *?
Для справки я получил термин «Закаленный жадный токен» отсюда: http://www.rexegg.com/regex-quantifiers.html#tempered_greed
- Regexp Java для проверки пароля
- Почему в Java 8 split иногда удаляет пустые строки при начале массива результатов?
- Обратные ссылки в lookbehind
- R - gsub заменяет обратную косую черту
- Какое лучшее регулярное выражение проверяет правильность строки?
- Как использовать замену новой строки в BSD sed?
- Как извлечь текст, который находится между круглыми скобками (круглые скобки)?
- Регулярное выражение, которое никогда не будет соответствовать чему-либо
Поскольку Google возвращает этот SO-запрос поверх результатов для tempered greedy token
, я чувствую себя обязанным предоставить более полный ответ.
Что такое закаленный жадный токен?
Упорядоченная лексическая ссылка rexegg.com довольно кратким:
В
(?:(?!{END}).)*
, Квантификатор*
применяется к точке, но теперь она является закаленной точкой. Отрицательный lookahead(?!{END})
утверждает, что то, что следует за текущей позицией, не является строкой{END}
. Поэтому точка никогда не сможет сопоставить открывающую скобку{END}
, гарантируя, что мы не будем перепрыгивать через разделитель{END}
.
Вот он: умеренный жадный токен – это своего рода отрицательный характерный class для последовательности символов (ср. Отрицательный class символов для одного символа ).
ПРИМЕЧАНИЕ . Разница между умеренным жадным токеном и отрицательным символьным classом заключается в том, что первый не соответствует тексту, отличному от самой последовательности, а является единственным символом , который не запускает эту последовательность. Ie (?:(?!abc|xyz).)+
будет соответствовать def
в defabc
, но будет соответствовать def
и bc
, потому что a
запускает запрещенную последовательность abc
, а bc
– нет.
Это состоит из:
-
(?:...)*
– количественная группа без захвата (это может быть группа захвата, но нет смысла захватывать каждый отдельный символ) (a*
может быть+
, это зависит от того, является ли пустая строка совпадением ожидается) -
(?!...)
– негативный взгляд, который фактически налагает ограничение на значение справа от текущего местоположения -
.
– (или любой (обычно одиночный) символ).
Тем не менее, мы всегда можем смягчить токен, используя чередование в негативном образе (например, (?!{(?:END|START|MID)})
) или путем замены точки совпадения на отрицательный class символов (например (?:(?!START|END|MID)[^<>])
при попытке сопоставить текст только внутри тегов).
Размещение расходных частей
Обратите внимание, что нет упоминания о конструкции, в которой потребляемая часть (точка в исходном закаленном жадном токене) помещается перед записью. Ответ Avinash объясняет эту часть ясно: (.(?!))*
сначала сопоставляет любой символ (но новую строку без модификатора DOTALL), а затем проверяет, не следует ли ему приводит к ошибке для соответствия
e
в
. Потребляемая часть ( .
) ДОЛЖНА быть размещена после закаливания .
Когда использовать умеренный алчный токен?
Rexegg.com дает представление:
- Когда мы хотим сопоставить блок текста между разделителем 1 и разделителем 2 без промежуточной подстроки 3 (например,
{START}(?:(?!{(?:MID|RESTART)}).)*?{END}
- Когда мы хотим сопоставить блок текста, содержащий конкретный шаблон внутри, без переполнения последующих блоков (например, вместо ленивого сопоставления точек, как в
, мы будем использовать что-то вроде
.*?chair.*?
(?:(?!chair|?table>).)*chair(?:(?!
).)*
- Когда мы хотим совместить кратчайшее окно между двумя строками. Lazy matching не поможет, когда вам нужно получить
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
не сопровождаются bc
(с a(?!bc)
) и всеми x
, не сопровождаемыми yz
(с x(?!yz)
): abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz
.
((?!).)*
будет проверять, что этот конкретный символ, который будет согласован, не должен быть начальным символом в строке . Если да, то только он соответствует этому конкретному символу.
*
повторяет то же самое ноль или более раз.
(.(?!))*
соответствует любому символу, только если за ним не следует , ноль или более раз. Таким образом, это будет соответствовать всем символам внутри тега таблицы excpet последнего символа, так как за последним символом следует
. И следующий шаблон
утверждает, что в конце матча должен быть тег закрывающей таблицы. Это приведет к сбою матча.
См. Здесь
Умеренный жадный токен на самом деле просто означает:
«матч, но только до точки»
как ты это делаешь:
вы помещаете токен, который вы не хотите сопоставлять, как отрицательный lookahead
(?!notAllowedToMatch)
перед точкой.
(соответствовать какой-либо одной вещи), то вы повторяете эту вещь со звездой*
:
((?!notAllowedToMatch).)*
как это работает:
«смотреть и есть один» снова и снова, перемещая один символ во времени слева направо через входную строку до тех пор, пока не увидите запрещенную последовательность (или конец строки), после чего совпадение остановится.
Более подробный ответ Wiktor хорош, я просто подумал, что более простое объяснение было в порядке.