Просмотр назад регулярного выражения не работает с квантификаторами ('+' или '*')

Я пытаюсь использовать ретроспективный просмотр в регулярном выражении, но, похоже, он работает не так, как я ожидал. Итак, это не мое реальное использование, но для упрощения я приведу пример. Представьте, что я хочу сопоставить «пример» со строкой, в которой говорится «это пример». Итак, согласно моему пониманию lookbehind, это должно работать:

(?<=this\sis\san\s*?)example

При этом нужно найти «this is an», затем пробел и наконец найти слово «example». Теперь это не работает, и я не понимаю, почему, невозможно использовать '+' или '*' внутри ретроспективы?

Я тоже пробовал эти два, и они работают правильно, но не соответствуют моим потребностям:

(?<=this\sis\san\s)example
this\sis\san\s*?example

Я использую этот сайт для проверки своих регулярных выражений: http://gskinner.com/RegExr/


person Noel De Martin    schedule 27.01.2012    source источник
comment
Для этого нужен тег, который идентифицирует язык или среду, в которой вы их используете. Регулярные выражения .NET справляются с этим без проблем.   -  person Joey    schedule 27.01.2012
comment
Уведомление! Если ваше регулярное выражение будет работать так, как вы хотите, оно также будет соответствовать example из этого: this is anexample. Поэтому, если вы этого не хотите, вам следует удалить ?   -  person noob    schedule 27.01.2012
comment
micha: Вероятно, им стоит просто поменять * на +. Удаление ? в этом отношении не имеет никакого эффекта. Но действительно, *? как квантификатор бесполезен и не нужен в этом случае, так как после этого больше нет пробелов, поэтому \s*? эквивалентно \s*.   -  person Joey    schedule 27.01.2012


Ответы (5)


Многие библиотеки регулярных выражений позволяют использовать только строгие выражения для проверки таких утверждений, как:

  • соответствует только строкам одинаковой фиксированной длины: (?<=foo|bar|\s,\s) (по три символа)
  • соответствует только строкам фиксированной длины: (?<=foobar|\r\n) (каждая ветвь фиксированной длины)
  • соответствует только строкам с длиной верхней границы: (?<=\s{,4}) (до четырех повторений)

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

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

См. Также раздел об ограничениях проверочных утверждений на Regular-Expressions.info.

person Gumbo    schedule 27.01.2012
comment
В мой ответ на этот вопрос , Я перечислил некоторые стратегии / обходные пути после того, как столкнулся с этим ограничением отрицательного просмотра назад. Надеюсь, это поможет и другим! - person Josh Withee; 12.02.2018

Привет, если вы не используете переменную python, смотрите за утверждением, вы можете обмануть механизм регулярных выражений, ускользнув от совпадения и начав заново, используя \K.

Этот сайт хорошо это объясняет .. http://www.phpfreaks.com/blog/pcre-regex-spotlight-k ..

Но в значительной степени, когда у вас есть выражение, которое вы соответствуете, и вы хотите получить все, что стоит за ним, использование \ K заставит его начать заново ...

Пример:

string = '<a this is a tag> with some information <div this is another tag > LOOK FOR ME </div>'

сопоставление /(\<a).+?(\<div).+?(\>)\K.+?(?=\<div)/ приведет к перезапуску регулярного выражения после сопоставления конечного тега div, поэтому регулярное выражение не будет включать его в результат. (?=\div) заставит движок получить все перед конечным тегом div

person Leon    schedule 27.07.2012
comment
это работает с ruby ​​2.x, но не работает с 1.9 и jruby 1.7.x; оригинальный комментарий: хорошо, я удивлен, что никогда не знал об этой функции. Научитесь форматировать код в редакторе, и вы будете бесценны - person akostadinov; 07.08.2014

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

(?<=this\sis\san)(?:\s*)example

Это делает его фиксированной длиной смотреть назад, так что он должен работать.

person Bohemian♦    schedule 27.01.2012
comment
Это то же самое, что и (?<=this\sis\san)\s*?example, что означает, что он также соответствует пробелам и, к вашему сведению, (?: ) замедляет процесс. - person noob; 27.01.2012
comment
micha, в таком случае я бы больше беспокоился о подходящей детали, чем о производительности. Я получаю в среднем 0,02451781 мс с группой без захвата и 0,02370844 мс без нее. Не думаю, что это существенная разница. - person Joey; 27.01.2012
comment
@micha Нет. Это не то же самое. Это группа без захвата. Мое регулярное выражение соответствует только example (без ведущих пробелов), но ваш пример включает ведущие пробелы - person Bohemian♦; 27.01.2012
comment
Это регулярное выражение будет соответствовать любым предыдущим пробелам. например this is an[ example]. (квадратные скобки обозначают совпадение). Тот факт, что он находится в группе, не связанной с захватом, не означает, что он не соответствует. Это просто означает, что он не попадает в группу, которая обычно помещается в обычные скобки. Правильный способ сделать это - использовать \K, как сказал @Leon - person Abraham Murciano Benzadon; 11.07.2017
comment
Это не работает. Ведущие пробелы включены в матч. Просто скопируйте и вставьте его на regex101.com. - person alstr; 19.05.2020

Большинство механизмов регулярных выражений не поддерживают выражения переменной длины для утверждений просмотра назад.

person Amber    schedule 27.01.2012
comment
Проблематично только взгляд назад. Lookahead может быть чем угодно во всех движках регулярных выражений, которые его поддерживают. - person Joey; 27.01.2012

Вы можете использовать подвыражения.

(this\sis\san\s*?)(example)

Итак, чтобы получить группу 2, «пример», $2 для регулярного выражения или \2, если вы используете строку формата (например, для re.sub в Python)

person WizKidd    schedule 21.10.2013