49

Python/PHP/JavaScript 中是否有正则表达式的实现支持可变长度的lookbehind-assertion?

/(?<!foo.*)bar/

如何编写具有相同含义但不使用后向断言的正则表达式?

这种类型的断言是否有可能在某一天实现?

事情比我想象的要好得多。

更新:

(1) 已经有支持变长lookbehind-assertion的正则表达式实现。

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 ikegami)。

我的其他问题:

  • 有没有可能说哪一点一定是最终的\K效果点?
  • Perl/Ruby/JavaScript/PHP 的增强正则表达式实现怎么样?类似于regexPython 的东西。
4

5 回答 5

48

大多数情况下,您可以通过使用\K.

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

将会

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

直到最后\K遇到的任何东西都不会被视为匹配的一部分(例如,出于替换的目的$&,等等)

负面的lookbehinds有点棘手。

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

将会

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

因为(?:(?!STRING).)*STRING那样。[^CHAR]*_CHAR


如果你只是匹配,你甚至可能不需要\K.

/foo.*bar/s

/^(?:(?!foo).)*bar/s
于 2012-07-24T22:57:50.290 回答
13

对于 Python,有一个支持可变长度后视的正则表达式实现:

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

它被设计为与标准 re 模块向后兼容。

于 2012-07-25T00:21:31.403 回答
5

您可以反转字符串和模式并使用可变长度前瞻

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

粗体匹配:

raboof rab7790oof raboo rabo rab rabo raboooof rabo

据我所知的原始解决方案:

Jeff 'japhy' Pinyan

于 2012-07-24T23:44:47.763 回答
2

您显示的正则表达式将找到其bar前面没有的任何foo实例。

一个简单的替代方法是首先匹配foo字符串,然后找到第一次出现的索引。然后搜索bar,看看是否可以找到该索引之前的事件。

如果您想查找bar直接以开头的实例,我还可以为此提供一个正则表达式(不使用lookbehind foo),但这会非常难看。基本上,颠倒/foo/- 即/[^f]oo|[^o]o|[^o]|$/

于 2012-07-24T23:03:26.417 回答
2
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))
>>> 

来源。

于 2016-01-19T04:18:35.440 回答