>>> 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(即Bin之前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'