找出Python正则表达式中的捕获组数量

时间:2008-09-24 13:14:50

标签: python regex

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

我希望能够做到这一点:

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的正则表达式似乎涵盖了所有基础,所以我将继续使用它。

7 个答案:

答案 0 :(得分:35)

def num_groups(regex):
    return re.compile(regex).groups

答案 1 :(得分:8)

f_x = re.search(...)
len_groups = len(f_x.groups())

答案 2 :(得分:2)

匹配对象的lastindex属性应该是您要查找的内容。请参阅re module docs

答案 3 :(得分:2)

来自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.要更改此值,令牌需要递归搜索。

答案 4 :(得分:1)

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

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

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

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

答案 5 :(得分:0)

可能是错的,但我认为没有办法找到正则表达式匹配后返回的组数。我能想到的唯一方法就是将你的特定正则表达式所期望的匹配数作为参数传递给你。

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

答案 6 :(得分:0)

以您的代码为基础:

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())