首页 > 解决方案 > 在正则表达式中使用组时 re.findall() 和 re.finditer() 之间的区别?

问题描述

考虑以下字符串

text2 = '''
Mr. Schafer
Mr Smith
Ms Davis
Mrs. Robinson
Mr. T
'''

我希望正则表达式匹配完整的名称,如 'Mr. 以谢弗为例

使用 finditer():

matches = re.finditer(r'(Mr|Ms|Mrs)\.?\s[A-Z]\w*', text2)
for match in matches:
    print(match)

结果:

<_sre.SRE_Match object; span=(1, 12), match='Mr. Schafer'>
<_sre.SRE_Match object; span=(13, 21), match='Mr Smith'>
<_sre.SRE_Match object; span=(22, 30), match='Ms Davis'>
<_sre.SRE_Match object; span=(31, 44), match='Mrs. Robinson'>
<_sre.SRE_Match object; span=(45, 50), match='Mr. T'>

finditer() 给了我想要的结果,但不在列表中。

但是当我使用 findall() 时:

re.findall(r'(Mr|Ms|Mrs)\.?\s[A-Z]\w*', text2)

结果:

['Mr', 'Mr', 'Ms', 'Mrs', 'Mr']

为什么是这样?如何使用 findall() 获得我想要的
结果我想要这个结果:

['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']

标签: pythonregextextregex-group

解决方案


返回的列表re.findall包含:

  • 每个匹配的文本,如果正则表达式没有捕获
  • 每个匹配中的捕获文本,如果正则表达式恰好有一个捕获
  • 如果正则表达式有多个捕获,则对应于每个捕获的子字符串元组。

捕获是正则表达式的一部分,用括号括起来,除非您使用(?:...); 在?:这种情况下,告诉 Python 的正则表达式库不要将括号视为定义捕获。(当然,它仍然用于分组。)

因此,最简单(可能也是最快)的解决方案是确保正则表达式没有捕获,方法是使用(?:...)包围标题而不是仅仅(...)

>>> re.findall(r'(?:Mr|Ms|Mrs)\.?\s[A-Z]\w*', text2)
['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']

您还可以显式捕获完整名称:

>>> re.findall(r'((?:Mr|Ms|Mrs)\.?\s[A-Z]\w*)', text2)
['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']

在这种情况下,这样做没有多大意义,但是如果您希望部分模式不显示在输出中,“一次捕获”形式可能会很有用。

最后,您可能需要一个元组中的敬语和姓氏:

>>> re.findall(r'(?:(Mr|Ms|Mrs)\.?\s([A-Z]\w*))', text2)
[('Mr', 'Schafer'), ('Mr', 'Smith'), ('Ms', 'Davis'), ('Mrs', 'Robinson'), ('Mr', 'T')]

推荐阅读