从一批正则表达式中获取第一个成功的匹配

时间:2010-09-04 14:09:28

标签: regex python

我正在尝试从一个可以匹配三种模式之一的字符串中提取数据集。我有一个已编译的正则表达列表。我想通过他们(按顺序)完成第一场比赛。

regexes = [
    compiled_regex_1,
    compiled_regex_2,
    compiled_regex_3,
]

m = None
for reg in regexes:
    m = reg.match(name)
    if m: break

if not m:
    print 'ARGL NOTHING MATCHES THIS!!!'

这应该有效(尚未测试),但它非常难看。有没有更好的方法来煮沸一个循环,当它成功时会中断,或者当它没有时会爆炸?

re可能存在一些我不了解的特定内容,允许您测试多个模式。

6 个答案:

答案 0 :(得分:6)

您可以使用for循环的else子句:

for reg in regexes:
    m = reg.match(name)
    if m: break
else:
    print 'ARGL NOTHING MATCHES THIS!!!'

答案 1 :(得分:2)

如果您只是想知道是否有任何正则表达式匹配,那么您可以使用内置any函数:

if any(reg.match(name) for reg in regexes):
     ....

然而,这不会告诉你哪个正则表达式匹配。

或者,您可以将多个模式合并为一个带有|的正则表达式:

regex = re.compile(r"(regex1)|(regex2)|...")

同样,这不会告诉您哪个正则表达式匹配,但您将拥有一个匹配对象,您可以使用该对象获取更多信息。例如,您可以找出哪个正则表达式来自非None的组:

>>> match = re.match("(a)|(b)|(c)|(d)", "c")
>>> match.groups()
(None, None, 'c', None)

然而,这可能会变得复杂,但是如果任何子正则表达式中也包含组,因为编号将会改变。

这可能比单独匹配每个正则表达式更快,因为正则表达式引擎有更多优化正则表达式的空间。

答案 2 :(得分:1)

由于在这种情况下你有一个有限集,你可以使用short ciruit evaluation

m = compiled_regex_1.match(name) or
    compiled_regex_2.match(name) or
    compiled_regex_3.match(name) or
    print("ARGHHHH!")

答案 3 :(得分:1)

在Python 2.6或更高版本中:

import itertools as it

m = next(it.ifilter(None, (r.match(name) for r in regexes)), None)

可以将ifilter调用转换为genexp,但只是有点笨拙,即在genexp中使用通常的名称绑定技巧(也就是“幻影嵌套for子句惯用法”) :

m = next((m for r in regexes for m in (r.match(name),) if m), None)

itertools通常更适用。

需要2.6的位是next内置的,如果迭代器耗尽,则允许您指定默认值。如果你必须在2.5或更早的时候模拟它,

def next(itr, deft):
  try: return itr.next()
  except StopIteration: return deft

答案 4 :(得分:0)

我使用像Dave Kirby建议的东西,但是将命名组添加到regexp中,以便我知道哪一个匹配。

regexps = {
  'first': r'...',
  'second': r'...',
}

compiled = re.compile('|'.join('(?P<%s>%s)' % item for item in regexps.iteritems()))
match = compiled.match(my_string)
print match.lastgroup

答案 5 :(得分:0)

Eric在更好地了解OP瞄准的目标方面处于更好的状态,但我会使用if else。我也认为在or表达式中使用print函数是有点可疑的。为Nathon +1修正OP以使用其他正确的声明。

然后我的另类:

# alternative to any builtin that returns useful result,
# the first considered True value
def first(seq):
    for item in seq:
        if item: return item

regexes = [
    compiled_regex_1,
    compiled_regex_2,
    compiled_regex_3,
]

m = first(reg.match(name) for reg in regexes)
print(m if m else 'ARGL NOTHING MATCHES THIS!!!')