你能解释为什么这个正则表达式不起作用吗?

时间:2011-06-16 20:32:58

标签: python regex negative-lookbehind

>>> d = "Batman,Superman"
>>> m = re.search("(?<!Bat)\w+",d)
>>> m.group(0)
'Batman'

为什么组(0)不匹配超人? This lookaround tutorial说:

  

(?&lt;!a)b匹配不是的“b”   前面是“a”,使用否定   回顾后发

5 个答案:

答案 0 :(得分:6)

{p> Batman {{}}

事实上,Bat也不是;在你的字符串中间有一个逗号,它可以很好地允许RE匹配,但是无论如何都不匹配,因为它可以在字符串的前面匹配。

也许这会更好地解释:如果字符串是Superman并且您开始尝试匹配Batman,则RE将不会匹配,直到后面的字符(给出m的匹配项,因为这是字符串中唯一以an开头的位置。

答案 1 :(得分:1)

从手册:

  

以负面开头的模式   lookbehind断言可能匹配   字符串的开头   搜索。

http://docs.python.org/library/re.html#regular-expression-syntax

答案 2 :(得分:1)

在一个简单的层面上,正则表达式引擎从字符串的左侧开始并逐渐向右移动,尝试匹配您的模式(将其视为移动通过字符串的光标)。在外观的情况下,在光标的每个停止处,断言是断言的,如果是,则引擎继续尝试进行匹配。一旦引擎可以匹配您的模式,它将返回匹配。

在你的字符串的第0位(即B中的Batman之前),断言成功,因为Bat在当前位置之前不存在 - 因此,{{ 1}}可以匹配整个单词\w+(请记住,正则表达式本质上是贪婪 - 即尽可能匹配。)

有关引擎内部的详细信息,请参阅this page


为了达到你想要的效果,你可以使用类似的东西:

Batman

在此模式中,引擎将匹配word boundary\b(?!Bat)\w+ 1 ,后跟一个或多个单词字符,并断言单词字符不从\b开始。使用 lookahead 而不是 lookbehind ,因为在这里使用lookbehind会遇到与原始模式相同的问题;它会直接跟在单词边界之后的位置之前,因为已经确定光标前的位置是一个单词边界,所以负面的后观将始终成功。

1 请注意,单词边界与Bat\w之间的边界匹配(即\W与任何其他字符之间的边界;它也匹配{{ 1}}和[A-Za-z0-9_] anchors)。如果你的边界需要更复杂,你需要一种不同的方式来锚定你的模式。

答案 3 :(得分:1)

您正在寻找第一组一个或多个字母数字字符(\w+),前面没有'Bat'。蝙蝠侠是第一场这样的比赛。 (注意,负向lookbehind断言可以匹配字符串的开头。)

答案 4 :(得分:1)

要做你想做的事,你必须将正则表达式限制为特别匹配'man';否则,正如其他人所指出的那样,\w贪婪地匹配任何内容,包括'Batman'。如:

>>> re.search("\w+(?<!Bat)man","Batman,Superman").group(0)
'Superman'