15

我需要在给定正则表达式的字符串中找到所有匹配项。我一直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()

  • 为什么行为不同?

  • 我怎样才能达到search()with findall() (或其他)的结果?

4

2 回答 2

19

好的,我看到了发生了什么......来自文档:

如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。

事实证明,你确实有一个组,“(\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) 返回您期望的结果。

于 2011-11-13T07:13:01.803 回答
7

@aleph_null 的回答正确解释了导致您的问题的原因,但我认为我有更好的解决方案。使用这个正则表达式:

regex = re.compile(r'\d+(?:,\d+)*')

为什么它更好的一些原因:

  1. (?:...)是一个非捕获组,因此每场比赛您只能得到一个结果。

  2. \d+(?:,\d+)*是一个更好的正则表达式,更有效且不太可能返回误报。

  3. 如果可能的话,你应该总是使用 Python 的原始字符串作为正则表达式;您不太可能对正则表达式转义序列(如word 边界)被解释为字符串文字转义序列(如\bbackspace 感到惊讶。\b

于 2011-11-13T08:11:28.987 回答