Какова техническая причина, по которой «lookbehind assertion ДОЛЖЕН быть фиксированной длиной» в регулярном выражении?

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

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

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

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

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

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

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

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

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

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

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

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

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

(1) использовать это:

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

(2) Или с \K :

 (src|href)="\Ketc. 

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

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

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

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

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

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

 (?<=,|^) 

с этим,

 (?:(?<=,)|^) 
 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 
  • Соответствие регулярных выражений в выражении Bash if
  • Прямоугольное соответствие Regex - Java
  • Возможно ли избежать метасимволов регулярных выражений с помощью sed
  • Проверка правильности выражения в jQuery
  • Как скопировать файл с именем, начинающимся с точки?
  • Как создать совпадение регулярных выражений?
  • Regex заменить все \ n на String, но не те внутри тега
  • Ошибка Tokenizing: java.util.regex.PatternSyntaxException, оборванный метасимвол '*'
  • Разделение Java ест моих персонажей
  • Как выполнить частичное совпадение с java.util.regex. *?
  • Java regex: Повторяющиеся группы захвата
  • Давайте будем гением компьютера.