2010-01-08 33 views
5

Tôi cần phải thử một chuỗi chống lại nhiều (độc quyền - có nghĩa là một chuỗi phù hợp với một trong số họ không thể phù hợp với bất kỳ khác) regexes, và thực hiện một đoạn mã khác nhau tùy thuộc vào một trong đó nó phù hợp. Những gì tôi đang có là:Làm cách nào để tìm kiếm thông qua các đối sánh regex bằng 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 

Ngoài sự xấu xí, mã này phù hợp chống lại tất cả regexes ngay cả sau khi nó đã xuất hiện một trong số họ (nói firstre), đó là không hiệu quả. Tôi đã cố gắng sử dụng:

elif m = secondre.match(str) 

nhưng đã học bài tập đó không được phép trong câu lệnh if.

Có cách nào thanh lịch để đạt được những gì tôi muốn không?

Trả lời

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 dành cho sự khiếp sợ thuần khiết. Cá nhân, tôi sẽ đưa danh sách các bộ dữ liệu ra ngoài câu lệnh for, ví dụ: 'match_functions = ((f1, re1), (f2, re2), ..)' và làm 'cho myfunc, myre trong match_functions:' – Kimvais

+1

Đừng quên thêm "break" để lưu cố gắng khớp với phần còn lại của danh sách. –

+0

Đã chỉnh sửa với các đề xuất của nhận xét cộng với ví dụ thực. –

1

Một vài ý kiến, không ai trong số họ tốt nhất thiết, nhưng nó có thể phù hợp với mã của bạn tốt:

Làm thế nào về cách đặt mã trong một chức năng riêng biệt, ví dụ: MatchRegex(), mà trả về mà regex nó phù hợp. Bằng cách đó, bên trong hàm, bạn có thể sử dụng trả lại sau khi bạn khớp với regex đầu tiên (hoặc thứ hai), có nghĩa là bạn mất đi sự thiếu hiệu quả.

Tất nhiên, bạn luôn có thể đi với chỉ lồng if báo cáo:

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

Tôi thực sự không nhìn thấy lý do nào đó không đi với lồng nhau if s. Chúng rất dễ hiểu và hiệu quả như bạn muốn. Tôi muốn đi cho họ chỉ vì sự đơn giản của họ.

+0

+1 để đề xuất giải pháp đơn giản cho vấn đề –

+0

nếu có vài trăm regex thì sao? mã sẽ khó đọc được cho bất cứ thứ gì trên 10 cái gì đó. – kibitzer

+0

@kibitzer: Trong trường hợp đó, nó có ý nghĩa để thiết kế một giải pháp chung. Hoặc trong trường hợp nó dự kiến ​​sẽ phát triển đến đó. Không phải mỗi lần bạn phải viết 3 lồng nhau nếu. –

3

Đây có thể là một chút kỹ thuật giải pháp, nhưng bạn có thể kết hợp chúng dưới dạng một regexp đơn với các nhóm được đặt tên và xem nhóm nào phù hợp. Điều này có thể được đóng gói như là một lớp helper:

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 

Lookup sẽ là như thế này:

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

Đẹp! (min 15 char) –

+0

Điều này xem xét kỹ thuật từ quan điểm của tôi. Tôi không tìm thấy mã thực sự dễ hiểu. –

0

lợi nhuận sớm, có lẽ?

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

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

    ... 

Kiến Câu trả lời của Aasma cũng tốt. Nếu bạn thích ít giàn giáo hơn, bạn có thể tự viết ra bằng cách sử dụng 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 
    ... 

Tôi đã làm điều này rất nhiều. Nó nhanh và hoạt động với re.finditer.

0

Làm điều đó với một elif trong trường hợp bạn chỉ cần một True/False ra khỏi khớp regex:

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

Tôi nghĩ rằng anh ta cần giá trị trả lại từ regex.match (str) –

1

Bạn có thể sử dụng

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

Vì vậy, ví dụ, nói rằng bạn đã xác định

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

Sau đó, gọi nó với

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

Đây là một ứng dụng tốt cho lớp học không có giấy tờ nhưng khá hữu ích re.Scanner.

+0

Rất tốt! Cảm ơn các liên kết. – Brandon

Các vấn đề liên quan