Python - 正则表达式搜索和查找所有
我需要在一个字符串中找到所有符合给定正则表达式的匹配项。我一直在用 findall()
来实现这个功能,直到我遇到一个情况,它的表现和我预期的不一样。例如:
regex = re.compile('(\d+,?)+')
s = 'There are 9,000,000 bicycles in Beijing.'
print re.search(regex, s).group(0)
> 9,000,000
print re.findall(regex, s)
> ['000']
在这个例子中,search()
返回了我需要的结果(最长的匹配),但是 findall()
的表现却不一样,尽管文档上说它们应该是一样的:
findall()
会匹配模式的所有出现,而不仅仅是像search()
那样匹配第一个。
为什么它们的行为会不同?
我怎么才能用
findall()
(或者其他方法)得到search()
的结果呢?
2 个回答
@aleph_null的回答正确地解释了导致你问题的原因,但我觉得我有一个更好的解决方案。使用这个正则表达式:
regex = re.compile(r'\d+(?:,\d+)*')
以下是为什么这个方案更好的几个原因:
(?:...)
是一个不捕获的分组,这样每次匹配时你只会得到一个结果。\d+(?:,\d+)*
是一个更好的正则表达式,它更高效,也更不容易出现错误匹配的情况。如果可能的话,使用Python的原始字符串来写正则表达式;这样你就不容易被正则表达式中的转义字符(比如
\b
表示“单词边界”)搞混成字符串中的转义字符(比如\b
表示“退格”)。
好的,我明白发生了什么……根据文档:
如果模式中有一个或多个分组,就会返回一个分组的列表;如果模式有多个分组,这将是一个元组的列表。
实际上,你确实有一个分组,“(\d+,?)”……所以,它返回的是这个分组的最后一个匹配结果,或者说是000。
一个解决办法是把整个正则表达式用一个分组包起来,像这样:
regex = re.compile('((\d+,?)+)')
这样,它会返回 [('9,000,000', '000')],这是一个包含两个匹配分组的元组。当然,你只关心第一个。
就我个人而言,我会使用以下的正则表达式:
regex = re.compile('((\d+,)*\d+)')
这样可以避免匹配到像“这是一个坏数字 9,123,”这样的内容。
编辑。
这里有一种方法,可以避免用括号包住表达式或处理元组:
s = "..."
regex = re.compile('(\d+,?)+')
it = re.finditer(regex, s)
for match in it:
print match.group(0)
finditer 返回一个迭代器,你可以用它来访问找到的所有匹配项。这些匹配对象和 re.search 返回的是一样的,所以 group(0) 会返回你期待的结果。