【问题标题】:Find out number of capture groups in Python regular expressions在 Python 正则表达式中找出捕获组的数量
【发布时间】:2010-09-12 17:26:28
【问题描述】:

有没有办法确定给定正则表达式中有多少个捕获组?

我希望能够做到以下几点:

def groups(regexp, s):
    """ Returns the first result of re.findall, or an empty default

    >>> groups(r'(\d)(\d)(\d)', '123')
    ('1', '2', '3')
    >>> groups(r'(\d)(\d)(\d)', 'abc')
    ('', '', '')
    """
    import re
    m = re.search(regexp, s)
    if m:
        return m.groups()
    return ('',) * num_of_groups(regexp)

这让我可以做以下事情:

first, last, phone = groups(r'(\w+) (\w+) ([\d\-]+)', 'John Doe 555-3456')

但是,我不知道如何实现num_of_groups。 (目前我只是解决它。)

编辑:advice from rslite 之后,我将re.findall 替换为re.search

sre_parse 似乎是最强大和最全面的解决方案,但需要遍历树,而且似乎有点重。

MizardX 的正则表达式似乎涵盖了所有基础,所以我将继续使用它。

【问题讨论】:

    标签: python regex


    【解决方案1】:
    def num_groups(regex):
        return re.compile(regex).groups
    

    【讨论】:

    • 这实际上不会返回组的数量,它将返回所有组的元组。为了返回组数,您需要以下代码(在 Python 3.4 中):return len(re.compile(regex).groups())
    • @RaziShaban re.compile(regex).groupsint 类型的属性。 re.compile(regex).match(input).groups() 是一个方法,返回一个tuple
    • 对,对不起,我正在使用 findall,而不是编译。我要说的是你的函数名为num_groups,但返回的是一个元组,而不是一个数字。
    • 我喜欢在完成 match = re.search() 或任何返回匹配对象后只使用 len(match.groups())。
    【解决方案2】:
    f_x = re.search(...)
    len_groups = len(f_x.groups())
    

    【讨论】:

    • 谢谢,最好的。不需要编译,已经编译好了。
    • 如果搜索失败,这将不起作用。在这种情况下,f_x 将为 None,因此它没有要检查的“组”属性。
    • @nupanick 所以需要检查if f_x: len(f_x.groups())
    【解决方案3】:

    sre_parse 内部的一些东西可能会有所帮助。

    乍一看,可能是这样的:

    >>> import sre_parse
    >>> sre_parse.parse('(\d)\d(\d)')
    [('subpattern', (1, [('in', [('category', 'category_digit')])])), 
    ('in', [('category', 'category_digit')]), 
    ('subpattern', (2, [('in', [('category', 'category_digit')])]))]
    

    即计算“子模式”类型的项目:

    import sre_parse
    
    def count_patterns(regex):
        """
        >>> count_patterns('foo: \d')
        0
        >>> count_patterns('foo: (\d)')
        1
        >>> count_patterns('foo: (\d(\s))')
        1
        """
        parsed = sre_parse.parse(regex)
        return len([token for token in parsed if token[0] == 'subpattern'])
    

    请注意,我们在这里仅计算根级别模式,因此最后一个示例仅返回 1。要更改这一点,tokens 需要递归搜索。

    【讨论】:

      【解决方案4】:

      首先,如果您只需要 re.findall 的第一个结果,最好只使用返回匹配项或 None 的 re.search。

      对于组数,您可以计算开括号 '(' 的数量,但那些被 '\' 转义的除外。您可以为此使用另一个正则表达式:

      def num_of_groups(regexp):
          rg = re.compile(r'(?<!\\)\(')
          return len(rg.findall(regexp))
      

      请注意,如果正则表达式包含非捕获组,并且如果 '(' 通过将其用作 '[(]' 进行转义,则此方法不起作用。所以这不是很可靠。但取决于您使用的正则表达式使用它可能会有所帮助。

      【讨论】:

        【解决方案5】:

        可能是错误的,但我认为没有办法找到匹配正则表达式时返回的组数。我能想到的使这项工作按您希望的方式工作的唯一方法是将您的特定正则表达式期望的匹配数作为参数传递。

        澄清一下:当 findall 成功时,您只希望返回第一个匹配项,但当它失败时,您想要一个空字符串列表?因为评论似乎显示所有匹配项都作为列表返回。

        【讨论】:

          【解决方案6】:

          以您的代码为基础:

          def groups(regexp, s):
              """ Returns the first result of re.findall, or an empty default
          
              >>> groups(r'(\d)(\d)(\d)', '123')
              ('1', '2', '3')
              >>> groups(r'(\d)(\d)(\d)', 'abc')
              ('', '', '')
              """
              import re
              m = re.search(regexp, s)
              if m:
                  return m.groups()
              return ('',) * len(m.groups())
          

          【讨论】:

          • 找不到匹配的时候会抛出异常
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-24
          • 2019-01-12
          • 1970-01-01
          • 1970-01-01
          • 2020-03-24
          相关资源
          最近更新 更多