Ответ 1
Так как Google возвращает этот вопрос SO поверх результатов для tempered greedy token
, я считаю необходимым предоставить более полный ответ.
Что такое закаленный жадный токен?
Ссылка rexegg.com умеренная лексика довольно кратка:
В
(?:(?!{END}).)*
квантор*
применяется к точке, но теперь она является закаленной точкой. Отрицательный lookahead(?!{END})
утверждает, что то, что следует за текущей позицией, не является строкой{END}
. Поэтому точка никогда не сможет сопоставить открывающую скобку{END}
, гарантируя, что мы не будем перепрыгивать через разделитель{END}
.
Вот он: умеренный жадный токен - это своего рода отрицательный класс символов для последовательности символов (см. отрицательный класс символов для одного символа).
ПРИМЕЧАНИЕ. Разница между умеренным жадным токеном и отрицательным символьным классом заключается в том, что первый не соответствует тексту, отличному от самой последовательности, а единственный символ, который не запускает эту последовательность, То есть (?:(?!abc|xyz).)+
не будет соответствовать def
в defabc
, но будет соответствовать def
и bc
, потому что a
запускается запрещенная последовательность abc
, а bc
- нет.
Он состоит из:
-
(?:...)*
- количественная группа, не захватывающая захват (это может быть группа захвата, но бессмысленно захватывать каждый отдельный символ) (a*
может быть+
, это зависит от того, пустая строка матч ожидается) -
(?!...)
- отрицательный результат, который фактически налагает ограничение на значение справа от текущего местоположения -
.
- (или любой (обычно один) символ) шаблон потребления.
Тем не менее, мы всегда можем смягчить токен, используя чередование в отрицательном образе (например, (?!{(?:END|START|MID)})
) или заменяя точку совпадения с помощью символа отрицательного символа (например, (?:(?!START|END|MID)[^<>])
при попытке сопоставить текст только внутри теги).
Размещение расходной части
Обратите внимание, что не упоминается конструкция, в которой потребляемая часть (точка в исходном закаленном жадном токене) помещается перед записью. Ответ Avinash ясно объясняет эту часть: (.(?!</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>
). - Если мы хотим совместить кратчайшее окно между двумя строками. 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
.