Подтвердить что ты не робот

Какая техническая причина для утверждения "lookbehind MUST be fixed length" в regex?

Например, приведенное ниже выражение будет вызывать отчет об ошибках утверждение lookbehind не фиксированная длина:

#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S

Такое ограничение не существует для lookahead.

4b9b3361

Ответ 1

Lookahead и lookbehind не так похожи, как их имена. Выражение lookahead работает точно так же, как если бы оно было автономным регулярным выражением, за исключением того, что оно привязано к текущей позиции совпадения и не использует то, что соответствует.

Lookbehind - это совсем другая история. Начиная с текущей позиции совпадения, он перемещается назад через текст по одному символу за раз, пытаясь сопоставить его выражение в каждой позиции. В случаях, когда совпадение невозможно, lookbehind должен пройти весь путь до начала текста (один символ за раз, помните), прежде чем он сдастся. Сравните это с выражением lookahead, которое применяется только один раз.

Это грубое упрощение, конечно, и не все вкусы работают таким образом, но вы получаете идею. Способ применения lookbehind принципиально отличается от (и намного, гораздо менее эффективным), чем применяются образы. Имеет смысл ограничивать, насколько далеко должен выглядеть внешний вид.

Ответ 2

Прежде всего, это неверно для всех библиотек регулярных выражений (например,.NET).

Для PCRE причина заключается в следующем:

Реализация lookbehind утверждения для каждой альтернативы, временно переместить текущий вернуть назад фиксированную ширину и затем попытайтесь сопоставить.

(по крайней мере, согласно http://www.autoitscript.com/autoit3/pcrepattern.html).

Ответ 3

PCRE не поддерживает плавающий lookbehind, потому что это может вызвать серьезные проблемы с производительностью. Это связано с отсутствием возможности совпадения справа налево: PCRE может начинать ветвь только с фиксированного левого, но левая сторона с переменной длиной lookbehind не может быть исправлена.

Как правило, попробуйте разделить свою часть lookbehind на шаблоны с фиксированной длиной, если это возможно. Например, вместо:

(?<=(src|href)=")etc.

(1) используйте это:

(?:(?<=src=")|(?<=href="))etc.

(2) Или с помощью \K:

(src|href)="\Ketc.

Обратите внимание, что \K не является реальным, потому что он всегда начинает поиск в конце предыдущего совпадения (нет никакого потенциального возврата в предыдущее совпадение).

(3) В некоторых сложных случаях lookbehind вы можете искать с помощью "инвертированного" выражения lookahead в обратной последовательности. Не слишком элегантный, но он работает:

.cte(?="=(ferh|crs))

Ответ 4

У меня была такая же проблема и исправлена ​​с помощью (?: subexpression)

Определяет незахватывающую группу. например Write(?:Line)? "WriteLine" в "Console.WriteLine()" "Write" в "Console.Write(значение)"

Мне пришлось изменить Regex, ниже которого предполагается поймать до , или что-то в начале строки, которая давала мне утверждение lookbehind не фиксированная длина.

(?<=,|^)

с этим,

(?:(?<=,)|^)

Ответ 5

grep -P '(?<=((three)|(one)) )two' <<< "one two three three two one"
grep: lookbehind assertion is not fixed length

grep -P '((?<=(three) )|(?<=(one) ))two' <<< "one two three three two one"
one two three three two one

Для эффективности обработки PCRE не поддерживает сопоставление справа налево или рекурсию. При выполнении "lookbehind" PCRE ищет конец любой предыдущей совпадающей строки - реализация совпадений с переменным размером потребует рекурсии и снизит эффективность. Смотрите: смотрите за утверждениями