Варианты с изменяемой длиной для поиска и выражения для регулярных выражений
Есть ли реализация регулярных выражений в 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))
>>>