2010-01-08 70 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