Есть ли реализация регулярных выражений в Python / PHP / JavaScript, которая поддерживает переменную длину lookbehind-assertion?
/(?<!foo.*)bar/
Как я могу написать регулярное выражение, имеющее то же значение, но не использующее lookbehind-assertion?
Есть ли вероятность, что этот тип утверждения будет реализован когда-нибудь?
Вещи намного лучше, чем я думал.
Обновить:
(1) Есть реализация регулярных выражений, которые уже поддерживают lookbehind-assert с переменной длиной.
Регулярный модуль 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
? regex
для Python. В большинстве случаев вы можете избежать искажений переменной длины с помощью \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 существует реализация регулярного выражения, которая поддерживает переменные длины lookbehinds:
http://pypi.python.org/pypi/regex
Он предназначен для обратной совместимости со стандартным модулем re.
Вы можете изменить строку И шаблон и использовать переменную длину lookahead
(rab(?!\w*oof)\w*)
Соответствует полужирным шрифтам:
raboof rab7790oof raboo rabof rab rabo rabooof rabo
Исходное решение, насколько я знаю:
Джефф 'japhy' Pinyan
Отображаемое регулярное выражение найдет любой экземпляр bar
которому не предшествует foo
.
Простой альтернативой было бы сначала foo
с строкой и найти индекс первого вхождения. Затем найдите bar
и посмотрите, сможете ли вы найти событие, которое появляется перед этим индексом.
Если вы хотите найти экземпляры bar
которым напрямую не предшествует foo
, я мог бы также предоставить regexp для этого (без использования lookbehind), но это будет очень уродливо. В принципе, инвертируем смысл /foo/
– ie /[^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)) >>>
Источник.