Варианты с изменяемой длиной для поиска и выражения для регулярных выражений

Есть ли реализация регулярных выражений в Python/PHP/JavaScript, которая поддерживает утверждение вида lookbehind-переменной?

/(?<!foo.*)bar/

Как я могу написать регулярное выражение, которое имеет то же значение, но не использует утверждение вида назад?

Есть ли вероятность, что этот тип утверждения когда-нибудь будет реализован?

Все намного лучше, чем я думал.

Обновить:

(1) Существуют реализации регулярных выражений, которые уже поддерживают утверждение взгляда переменной длины.

Модуль регулярных выражений Python (не стандартный re, но дополнительный regex Модуль) поддерживает такие утверждения (и имеет много других интересных функций).

>>> import regex
>>> m = regex.search('(?<!foo.*)bar', 'f00bar')
>>> print m.group()
bar
>>> m = regex.search('(?<!foo.*)bar', 'foobar')
>>> print m
None

Для меня было большим сюрпризом, что в регулярных выражениях есть что-то, чего не может Perl, а Python - нет. Возможно, для Perl также есть реализация "расширенного регулярного выражения"?

(Спасибо и +1 к MRAB).

(2) есть классная особенность \K в современных регулярных выражениях.

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

s/unchanged-part\Kchanged-part/new-part/x

Это почти как предположение, но, конечно, не так гибко.

Больше о \K:

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

(Спасибо и +1 к икегам).

Мои дополнительные вопросы:

  • Можно ли сказать, какая точка должна быть конечной точкой \K эффект?
  • Как насчет расширенных реализаций регулярных выражений для Perl/Ruby/JavaScript/PHP? Что-то вроде regex для Python.

5 ответов

Решение

Большую часть времени вы можете избежать просмотра за переменную длину, используя \K,

s/(?<=foo.*)bar/moo/s;

было бы

s/foo.*\Kbar/moo/s;

Отрицательные взгляды немного сложнее.

s/(?<!foo.*)bar/moo/s;

было бы

s/^(?:(?!foo).)*\Kbar/moo/s;

так как (?:(?!STRING).)* это к STRING как [^CHAR]* это к CHAR,


Если вы просто соответствуете, вам может даже не понадобиться \K,

/foo.*bar/s

/^(?:(?!foo).)*bar/s

Для Python есть реализация регулярного выражения, которая поддерживает просмотр за разной длины:

http://pypi.python.org/pypi/regex

Он разработан для обратной совместимости со стандартным модулем re.

Вы можете перевернуть строку И шаблон и использовать переменную длину

(rab(?!\w*oof)\w*)

совпадения, выделенные жирным шрифтом:

raboof rab7790oof raboo rabof rab rabo raboooof rabo

Оригинальное решение, насколько я знаю, по:

Джефф 'japhy' Пиньян

Регулярное выражение, которое вы показываете, найдет любой экземпляр bar которому не предшествует foo,

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

Если вы хотите найти экземпляры bar которым непосредственно не предшествует fooЯ мог бы также предоставить регулярное выражение для этого (без использования lookbehind), но это будет очень уродливо. В основном, инвертировать смысл /foo/ - т.е. /[^f]oo|[^o]o|[^o]|$/,

foo.*|(bar)

Если foo сначала в строке, затем регулярное выражение будет соответствовать, но групп не будет.

В противном случае он найдет bar и назначить его группе.

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

>>> import re
>>> m = re.search('foo.*|(bar)', 'f00bar')
>>> if m: print(m.group(1))
bar
>>> m = re.search('foo.*|(bar)', 'foobar')
>>> if m: print(m.group(1))
None
>>> m = re.search('foo.*|(bar)', 'fobas')
>>> if m: print(m.group(1))
>>> 

Источник.

Другие вопросы по тегам