在Python正则中使用正向查找时遇到问题

1 投票
3 回答
2601 浏览
提问于 2025-04-15 14:32

我在使用一个比较长的正则表达式时,发现有一小部分没有按照我预期的方式匹配。

>>> re.search(r'(foo)((?<==)bar)?', 'foo').groups()
('foo', None)

>>> re.search(r'(foo)((?<==)bar)?', 'foo=bar').groups()
('foo', None)

我想要的是第一个匹配结果,而第二个应该返回 ('foo', 'bar')

我怀疑我对“向后查找”这个概念理解得不太对,如果能解释一下就太好了。

3 个回答

0

你为什么不直接用这个呢:

(foo)=?(bar)?

还有,下面这个表达式似乎更准确,因为它能把'='也包含在完整匹配中,而你原来的表达式根本没有把它包含进去:

(foo).?((?<==)bar)?
1

你可能只想用一个不捕获的分组 (foo)(?:=(bar))?

一个向后查找的断言就是在当前的位置左边查看,检查提供的表达式是否匹配。因此,你的表达式会匹配 foo,然后检查左边的内容——也就是 foo 中的第二个 o 是否匹配 =。这当然总是会失败。

2

在正则表达式中,"look behind"(向后查看)这个目标是不会被包含在匹配结果里的。它的作用是作为一个锚点,但实际上并不会被正则表达式消耗掉。

向后查看的模式只有在当前的位置前面有目标时才会匹配。在你的例子中,当匹配到字符串中的"foo"后,当前的位置是在"="上,而这个位置前面并没有"=",而是前面是"o"。

另一种理解这个概念的方法是查看re文档,里面提到:

注意,任何以正向向后查看断言开头的模式在被搜索的字符串的开头是永远不会匹配的;

在你匹配到foo后,你的向后查看尝试在(剩余部分的)字符串开头进行匹配——这永远是行不通的。

其他人也提出了一些可能更适合你的正则表达式,但我觉得你可能在寻找的是

>>> re.search('(foo)(=(bar))?', 'foo=bar').groups()
('foo', '=bar', 'bar')

如果你觉得多出来的分组有点烦,可以去掉里面的"()",然后直接把匹配到的组的第一个字符去掉……

撰写回答