>>> d = "Batman,Superman"
>>> m = re.search("(?<!Bat)\w+",d)
>>> m.group(0)
'Batman'
为什么 group(0) 不匹配超人?这个环视教程说:
(?<!a)b 匹配前面没有“a”的“b”,使用否定的lookbehind
>>> d = "Batman,Superman"
>>> m = re.search("(?<!Bat)\w+",d)
>>> m.group(0)
'Batman'
为什么 group(0) 不匹配超人?这个环视教程说:
(?<!a)b 匹配前面没有“a”的“b”,使用否定的lookbehind
Batman
不是直接在前面,Bat
所以首先匹配。事实上,两者都不是Superman
;在您的字符串之间有一个逗号可以很好地允许该 RE 匹配,但无论如何都不匹配,因为它可以在字符串中更早地匹配。
也许这会更好地解释:如果字符串是Batman
并且您开始尝试从 匹配m
,则 RE 将不匹配直到后面的字符(匹配an
),因为这是字符串中唯一以 . 开头的位置Bat
。
简单来说,正则表达式引擎从字符串的左侧开始并逐渐向右移动,试图匹配您的模式(将其想象为光标在字符串中移动)。在环视的情况下,在光标的每个停止处,都会断言环视,如果为真,引擎会继续尝试进行匹配。一旦引擎可以匹配您的模式,它就会返回一个匹配项。
在字符串的位置 0(即B
in之前Batman
),断言成功,因为Bat
在当前位置之前不存在 - 因此,\w+
可以匹配整个单词Batman
(请记住,正则表达式本质上是贪婪的- 即。将匹配尽可能多可能的)。
有关引擎内部结构的更多信息,请参阅此页面。
为了实现你想要的,你可以使用类似的东西:
\b(?!Bat)\w+
在此模式中,引擎将匹配单词边界( \b
) 1,后跟一个或多个单词字符,并断言单词字符不以 开头Bat
。使用前瞻而不是后向,因为在这里使用后向会与原始模式存在相同的问题;它会在紧跟单词边界的位置之前查找,并且由于已经确定光标之前的位置是单词边界,因此否定向后查找总是会成功。
1请注意,单词边界匹配 and 之间的边界\w
(\W
即 between [A-Za-z0-9_]
and 任何其他字符;它也匹配^
and$
锚点)。如果您的边界需要更复杂,您将需要一种不同的方式来锚定您的模式。
您正在寻找\w+
前面没有“Bat”的第一组一个或多个字母数字字符 ( )。蝙蝠侠是第一个这样的比赛。(请注意,否定的后向断言可以匹配字符串的开头。)
为了做你想做的事,你必须约束正则表达式来'man'
专门匹配;否则,正如其他人所指出的那样,\w
贪婪地匹配任何东西,包括'Batman'
. 如:
>>> re.search("\w+(?<!Bat)man","Batman,Superman").group(0)
'Superman'