Альтернативные альтернативы 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))
>>> 

Источник