python - 正则表达式搜索和findall

arm*_*ino 15 python regex search string-matching findall

我需要在给定正则表达式的字符串中找到所有匹配项.我一直在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']
Run Code Online (Sandbox Code Playgroud)

在这种情况下search()返回我需要的(最长匹配)但findall()行为不同,虽然文档暗示它应该是相同的:

findall()匹配所有出现的模式,而不仅仅是第一个模式search().

  • 为什么行为不同?

  • 我怎样才能实现的结果search()findall() (或别的东西)?

ale*_*ull 18

好的,我从文档中看到了...

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

事实证明,你有一个组,"(\ d +,?)"......所以,它返回的是该组的最后一次出现,或000.

一种解决方案是围绕整个正则表达式,像这样

regex = re.compile('((\d+,?)+)')
Run Code Online (Sandbox Code Playgroud)

然后,它将返回[('9,000,000','000')],这是一个包含两个匹配组的元组.当然,你只关心第一个.

就个人而言,我会使用以下正则表达式

regex = re.compile('((\d+,)*\d+)')
Run Code Online (Sandbox Code Playgroud)

避免匹配"这是一个坏号码9,123"之类的东西

编辑.

这是一种避免用括号括起表达式或处理元组的方法

s = "..."
regex = re.compile('(\d+,?)+')
it = re.finditer(regex, s)

for match in it:
  print match.group(0)
Run Code Online (Sandbox Code Playgroud)

finditer返回一个迭代器,您可以使用它来访问找到的所有匹配项.这些匹配对象与re.search返回的相同,因此group(0)返回您期望的结果.


Ala*_*ore 7

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

regex = re.compile(r'\d+(?:,\d+)*')
Run Code Online (Sandbox Code Playgroud)

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

  1. (?:...) 是一个非捕获组,因此您只能获得每个匹配的一个结果.

  2. \d+(?:,\d+)* 是一个更好的正则表达式,更高效,更不容易返回误报.

  3. 如果可能的话,你应该总是使用Python的原始字符串作为正则表达式; 你就不太可能通过正则表达式转义序列(如惊讶\b字边界)被解释为字符串字面转义序列(如\b退格键).

  • 没问题!但是,为了记录,允许用户输入由您的应用程序执行的正则表达式是一个坏主意.当他们写得不好(或者只是匆匆打字)的正则表达式无法匹配,或者系统崩溃时,他们会为此归咎于你*.;) (2认同)