2010-09-04 70 views
3

我试图从一个字符串中提取一组数据,该字符串可以匹配三种模式中的一种。我有一个编译正则表的列表。我想穿过他们(按顺序),并与第一场比赛。从一批正则表达式中取得第一个成功匹配

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

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

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

+1正确的,但我已经得到的印象是,对-else结构被认为是混乱,尽管许多情况下,它到底是什么你希望它似乎皱起了眉头(但我很想被驳斥)。 – msw 2010-09-04 14:18:23

+0

不知道那个。尽管我的眼睛总是将'else'与'try'联系起来,除了'语句外,它用'try' ...'把我赶出去了。 – 2010-09-04 14:19:45

+0

我已经至少三次了解到'for..else' ...我一直在忘记它。这只是不好的命名,但它确实工作。谢谢。 – Oli 2010-09-04 14:23:12

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!") 
2

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

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

但是这不会告诉你哪个正则表达式匹配。

或者您可以将多个图案合并为一个单一的正则表达式与|

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

同样,这不会告诉你它正则表达式匹配,但你将有一个匹配的对象,您可以使用以获取更多信息。例如,你可以找出哪些正则表达式的从小组成功不是无:

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

但是这样做会变得复杂,但是如果任何子正则表达式的有组他们为好,因为编号将被改变。

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

0

我使用类似Dave Kirby的建议,但是将命名组添加到正则表达式中,以便我知道哪一个匹配。

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 
+0

请注意,正则表达式尝试的顺序将是未定义的,这可能会产生意想不到的结果。 – 2010-09-04 22:46:19

+0

对,因为我用了字典。如果您使用元组列表来替代,或者在列表理解中对regexps.items进行排序,那么它是很好定义的。 – 2010-09-05 22:58:45

0

埃里克在更好地了解OP的目标是什么,但如果还有其他问题,我会用。我也认为在or表达式中使用打印功能是没有问题的。 Nathon修正OP使用适当的else语句+1。

然后我选择:

# 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!!!') 
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 
相关问题