【问题标题】:Difference between re.findall() and re.finditer() when using groups in regex?在正则表达式中使用组时 re.findall() 和 re.finditer() 之间的区别?
【发布时间】:2021-01-11 11:02:01
【问题描述】:

考虑以下字符串

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

【问题讨论】:

  • 您需要使组不捕获:re.findall(r'(?:Mr|Ms|Mrs)\.?\s[A-Z]\w*', text2),否则它将返回捕获的组而不是整个匹配的模式。
  • 我更喜欢 finditer 而不是 findall 因为 iter 不会将整个数据读取到 RAM,因为它返回一个迭代,而 find all 返回一个列表。要获取值,只需使用.group()。请参阅下面的示例。

标签: python regex text regex-group


【解决方案1】:

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')]

【讨论】:

    【解决方案2】:

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

    添加“?:”设置不捕获。

    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 Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']
    

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

    【讨论】:

      【解决方案3】:

      比起findall,我更喜欢finditerfinditer 返回文本中匹配对象的迭代器,而 findall 返回文本中匹配模式的列表。对于有效性,生成器比 list as 将所有读取数据列出到内存中要好,而 tier 没有。要从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)
      

      【讨论】:

        猜你喜欢
        • 2013-12-17
        • 2012-06-01
        • 2013-09-18
        • 2016-11-18
        • 2012-02-22
        • 2023-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多