Python re:否定正则表达式的一部分

1 投票
3 回答
8092 浏览
提问于 2025-04-17 07:20

也许这个问题听起来有点傻,但虽然谷歌找到了很多类似的情况,我还是没能找到这个确切的情况:什么样的正则表达式可以匹配所有不包含特定字符串的字符串。例如,我想匹配任何不包含 'foo_' 的字符串。

 re.match('(?<!foo_).*', 'foo_bar') 

这个会返回匹配结果。而

re.match('(?<!foo_)bar', 'foo_bar')

这个则不会。

我试过非贪婪版本:

 re.match('(?<!foo_).*?', 'foo_bar')

还是会返回匹配结果。

如果我在后面加上更多字符,

re.search('(?<!foo_)b.*', 'foo_bar')

它就返回 None,但如果目标字符串后面有更多字符:

re.search('(?<!foo_)b.*', 'foo_barbaric')

它又会返回匹配结果。

我故意没有在正则表达式开头加上 .* 或 .*?。但加上后也会出现同样的情况。

有没有人知道为什么会有这种奇怪的行为?(我需要这个作为一个单一的正则表达式 - 以便用户输入)。

3 个回答

0

我觉得你可以通过一个条件语句来解决这个问题,这样设计起来会更简单。

如果我们知道你具体想要实现什么,那就更好了。

为什么不试试这样做呢:

if not re.match("foo", something):
    do_something
else:
    print "SKipping this"
3

试试这个模式:

^(?!.*foo_).*

这个模式使用了 ^ 这个特殊符号,它的作用是从字符串的开头开始匹配。接着,它使用了一种叫做负向前瞻的技巧,来检查字符串中是否有 "foo_" 这个部分。如果有的话,匹配就会失败。

因为你给出的例子中用了 re.match()re.search() 两种方法,上面的模式在这两种方法中都能用。不过,当你使用 re.match() 的时候,可以放心地不使用 ^ 这个符号,因为它默认就是从字符串的开头开始匹配。而 re.search() 则是可以在字符串的任何位置进行匹配。

4

你在使用“向后查找”的方法,但其实应该用“向前查找”的方法:

re.match(r"(?!.*foo_).*", "foo_bar")

这样做是有效的(也就是说,不会匹配到)。

(?!.*foo_)的意思是“确认从当前字符串的位置开始,无法匹配到.*foo_”。因为你使用的是re.match(),所以这个位置自动被定义为字符串的开头。

撰写回答