如何返回匹配某些文本的正则表达式?

时间:2016-03-11 22:27:15

标签: python regex python-3.x

Javascript正则表达式问题Return the part of the regex that matched的答案是“不,因为编译会破坏正则表达式文本和匹配逻辑之间的关系。”

但Python保留Match Objectsre.groups()返回触发匹配的特定组。将每个组的正则表达式文本保留为匹配对象的一部分并返回它应该很简单,但似乎没有调用这样做。

import re

pat = "(^\d+$)|(^\w+$)|(^\W+$)"
test = ['a', 'c3', '36d', '51', '29.5', '#$%&']
for t in test:
    m = re.search(pat, t)
    s = (m.lastindex, m.groups()) if m else ''
    print(str(bool(m)), s)

返回:

True (2, (None, 'a', None))
True (2, (None, 'c3', None))
True (1, ('51', None, None))
False
True (3, (None, None, '#$%&'))

编译器显然知道这种模式中有三个组。有没有办法在正则表达式中提取每个组中的子模式,例如:

>>> print(m.regex_group_text)

('^\d+$', '^\w+$', '^\W+$')

是的,可以编写自定义模式解析器,例如拆分“|”对于这种特殊的模式。但是,使用re编译器对每个组中文本的理解会更容易,更可靠。

3 个答案:

答案 0 :(得分:5)

如果索引不够并且您绝对需要知道正则表达式的确切部分,则可能没有其他可能性,只能自己解析表达式组。 / p>

总而言之,这没什么大不了的,因为你可以简单地计算开始和结束括号并记录它们的指数:

def locateBraces(inp):
    bracePositions = []
    braceStack = []
    depth = 0
    for i in range(len(inp)):
        if inp[i] == '(':
            braceStack.append(i)
            depth += 1
        if inp[i] == ')':
            bracePositions.append((braceStack.pop(), i))
            depth -= 1
            if depth < 0:
                raise SyntaxError('Too many closing braces.')
    if depth != 0:
        raise SyntaxError('Too many opening braces.')
    return bracePositions
  

编辑:这个愚蠢的实现只计算开始和结束括号。但是,正则表达式可能包含转义大括号,例如\(,是   使用此方法计算为常规的组定义括号。你可以   想要调整它以省略数量不均匀的大括号   在它们之前的反斜杠。我把这个问题留给你作为一项任务;)

使用此功能,您的示例变为:

pat = "(^\d+$)|(^\w+$)|(^\W+$)"
bloc = locateBraces(pat)

test = ['a', 'c3', '36d', '51', '29.5', '#$%&']
for t in test:
    m = re.search(pat, t)
    print(str(bool(m)), end='')
    if m:
        h = bloc[m.lastindex - 1]
        print(' %s' % (pat[h[0]:h[1] + 1]))
    else:
        print()

返回:

True (^\w+$)
True (^\w+$)
True (^\w+$)
True (^\d+$)
False
True (^\W+$)
  

已编辑:要获取您的论坛列表,当然可以做一个简单的理解:

gtxt = [pat[b[0]:b[1] + 1] for b in bloc]

答案 1 :(得分:4)

根据您实际尝试解决的问题,这可能会有所帮助,也可能没有帮助......但python允许您为这些组命名:

r = re.compile('(?P<int>^\d+$)|(?P<word>^\w+$)')

从那里,当你有匹配时,你可以检查groupdict以查看哪些组存在:

r.match('foo').groupdict()  # {'int': None, 'word': 'foo'}
r.match('10').groupdict()  # {'int': '10', 'word': None}

当然,这并不能告诉您与比赛相关的确切正则表达式 - 您需要根据组名自行跟踪。

如果你真的想要超越这个,你可能想要比简单的正则表达式解析更复杂的东西。在这种情况下,我可能会建议像pyparsing这样的东西。不要让网站上的旧式样式欺骗你(或缺少符合PEP-8的API) - 一旦你习惯了库,这个库实际上非常强大。

答案 2 :(得分:2)

您仍然需要跟踪正在为re.search提供的正则表达式。类似的东西:

import re

patts = {
  'a': '\d+',
  'b': '^\w+',
  'c': '\W+'
}

pat = '^' + '|'.join('({})'.format(x) for x in patts.values()) + '$'
test = ['a', 'c3', '36d', '51', '29.5', '#$%&']
for t in test:
    m = re.search(pat, t)
    if m:
      for g in m.groups():
        for key, regex in patts.iteritems():
          if g and re.search(regex, g):
            print "t={} matched regex={} ({})".format(t, key, regex)
            break