2010-01-08 79 views
5

我需要针对多个(独占 - 意味着匹配其中一个字符串的字符串不能匹配任何其他字符串)正则表达式的字符串,并根据匹配的哪一个执行不同的代码段。我有什么目前:如何通过Python搜索正则表达式匹配?

m = firstre.match(str) 
if m: 
    # Do something 

m = secondre.match(str) 
if m: 
    # Do something else 

m = thirdre.match(str) 
if m: 
    # Do something different from both 

除了丑陋,这段代码对所有的正则表达式匹配它匹配即使其中一人(比如说firstre),这是低效的。我试图使用:

elif m = secondre.match(str) 

但获悉if语句中不允许赋值。

有没有一种优雅的方式来实现我想要的?

回答

4
def doit(s): 

    # with some side-effect on a 
    a = [] 

    def f1(s, m): 
     a.append(1) 
     print 'f1', a, s, m 

    def f2(s, m): 
     a.append(2) 
     print 'f2', a, s, m 

    def f3(s, m): 
     a.append(3) 
     print 'f3', a, s, m 

    re1 = re.compile('one') 
    re2 = re.compile('two') 
    re3 = re.compile('three') 


    func_re_list = (
     (f1, re1), 
     (f2, re2), 
     (f3, re3), 
    ) 
    for myfunc, myre in func_re_list: 
     m = myre.match(s) 
     if m: 
      myfunc(s, m) 
      break 


doit('one') 
doit('two') 
doit('three') 
+0

+1纯pythonic迷人。就个人而言,我会把元组列表放在for语句之外,例如'match_functions =((f1,re1),(f2,re2),..)'并且为myfunc,myre在match_functions:' – Kimvais 2010-01-08 14:45:48

+1

不要忘记添加“break”来保存尝试匹配其余部分列表。 – 2010-01-08 14:46:26

+0

编辑与意见的建议加真实的例子。 – 2010-01-08 14:55:05

1

一些想法,他们没有很好的必然,但它可能适合你的代码以及:

如何把代码中的一个单独的函数,即MatchRegex(),它返回它的正则表达式匹配。这样,在函数内部,您可以在匹配第一个(或第二个)正则表达式后使用返回值,这意味着您将失去低效率。

当然,你总是可以只用嵌套if语句去:

m = firstre.match(str) 
if m: 
    # Do something 
else: 
    m = secondre.match(str) 
    ... 

我实在看不出有什么理由不去嵌套if秒。他们非常容易理解,并且可以随心所欲。我会为了他们的简单而去追求他们。

+0

+1表示问题的简单解决方案 – 2010-01-08 16:46:29

+0

如果有几百个正则表达式,该怎么办?对于任何超过10个事物的代码都难以阅读。 – kibitzer 2010-01-10 02:13:58

+0

@kibitzer:在这种情况下,设计一个通用解决方案是有意义的。或者在预计会增长到这种情况。不是每次你必须写3个嵌套的if。 – 2010-01-10 08:32:13

3

这可能在解决方案的设计上有点过分,但可以将它们组合为具有命名组的单个正则表达式并查看哪些组匹配。这可以被封装为一个辅助类:

import re 
class MultiRe(object): 
    def __init__(self, **regexps): 
     self.keys = regexps.keys() 
     self.union_re = re.compile("|".join("(?P<%s>%s)" % kv for kv in regexps.items())) 

    def match(self, string, *args): 
     result = self.union_re.match(string, *args) 
     if result: 
      for key in self.keys: 
       if result.group(key) is not None: 
        return key 

查询会是这样的:

multi_re = MultiRe(foo='fo+', bar='ba+r', baz='ba+z') 
match = multi_re.match('baaz') 
if match == 'foo': 
    # one thing 
elif match == 'bar': 
    # some other thing 
elif match == 'baz': 
    # or this 
else: 
    # no match 
+0

不错! (最少15个字符) – 2010-01-08 18:20:44

+0

这从我的角度来看看工程。我不觉得代码真的很容易理解。 – 2010-01-08 18:31:31

0

早期的回报,也许?

def doit(s): 
    m = re1.match(s) 
    if m: 
     # Do something 
     return 

    m = re2.match(s) 
    if m: 
     # Do something else 
     return 

    ... 

蚂蚁Aasma的回答也很好。如果您不喜欢脚手架,可以使用verbose regex syntax自己写出。

re = re.compile(r'''(?x) # set the verbose flag 
    (?P<foo> fo+) 
    | (?P<bar> ba+r) 
    | #...other alternatives... 
''') 

def doit(s): 
    m = re.match(s) 
    if m.group('foo'): 
     # Do something 
    elif m.group('bar'): 
     # Do something else 
    ... 

我已经做了很多。它速度很快,它可以与re.finditer一起使用。

0

做它用的情况下,一个ELIF你只需要一个真/假了正则表达式匹配的:

if regex1.match(str): 
    # do stuff 
elif regex2.match(str): 
    # and so on 
+1

我认为他需要regex.match(str) – 2010-01-08 16:47:43

1

你可以使用

def do_first(str, res, actions): 
    for re,action in zip(res, actions): 
    m = re.match(str) 
    if m: 
     action(str) 
     return 

因此,举例来说,假设你已经定义

def do_something_1(str): 
    print "#1: %s" % str 

def do_something_2(str): 
    print "#2: %s" % str 

def do_something_3(str): 
    print "#3: %s" % str 

firstre = re.compile("foo") 
secondre = re.compile("bar") 
thirdre = re.compile("baz") 

然后用

叫它
do_first("baz", 
     [firstre,  secondre,  thirdre], 
     [do_something_1, do_something_2, do_something_3]) 
3

这是一个很好的应用程序的无证,但相当有用的re.Scanner类。

+0

的返回值不错!感谢您的链接。 – Brandon 2010-01-08 18:18:06