问题描述
考虑以下字符串
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
相比,我更喜欢findall
。 finditer
返回文本中匹配对象的迭代器,而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)