在正则表达式中使用组时,re.findall和re.finditer之间的区别?

问题描述

考虑以下字符串

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

我希望正则表达式匹配全名,例如'Mr.例如Schafer'

使用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']

解决方法

re.findall返回的列表包含:

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

除非使用(?:...),否则捕获是正则表达式中包含括号的部分。 ?:在这种情况下告诉Python的regex库不要将括号视为定义捕获。 (它仍然用于分组课程。)

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

>>> 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*)','Mr. T']

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

最后,您可能希望元组中既有素名又有姓氏:

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

“()”部分是捕获指示符。

添加“?:”以设置非捕获。

import re

text2 = '''
        Mr. Schafer
        Mr Smith
        Ms Davis
        Mrs. Robinson
        Mr. T
        '''
print(re.findall(r"(?:Mr|Ms|Mrs)\.?\s[A-Za-z]*w*",text2))
# ['Mr. Schafer','Mr. T']

https://regexr.com/ 左侧有一个备忘单。

,

finditer相比,我更喜欢findallfinditer返回文本中匹配对象的迭代器,而findall返回文本中匹配模式的列表。为了提高效率,生成器比将所有读取的数据都列出为列表更好,而层级则不是。要从iterator获取值,只需使用.group()

import re

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


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

match_list = [match.group() for match in matches]
print(match_list)