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