Как я перерываю соответствия regex в Python?

Я должен попробовать строку против нескольких (эксклюзивный - значение строки, которая соответствует одному из них, не может соответствовать ни одному из другого), regexes, и выполните другую часть кода, в зависимости от которого это соответствует. Что я имею, в настоящее время:

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

Кроме уродства, этот код соответствует против всего regexes даже после того, как это соответствовало одному из них (скажите, что firstre), который неэффективен. Я пытался использовать:

elif m = secondre.match(str)

но изученный, что присвоению не позволяют войти если операторы.

Существует ли изящный способ достигнуть того, что я хочу?

5
задан sundar - Reinstate Monica 8 January 2010 в 14:28
поделиться

7 ответов

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' ) 
4
ответ дан 13 December 2019 в 05:36
поделиться

Несколько идей, ни одна из них не обязательно хороша, но она может хорошо подойти к вашему коду:

Как насчет того, чтобы поместить код в отдельную функцию, т.е. MatchRegex(), которая возвращает тот регекс, которому он соответствовал. Таким образом, внутри функции можно использовать возврат после совпадения первого (или второго) регрекса, то есть потерять эффективность.

Конечно, вы всегда можете использовать только вложенные , если высказывания:

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

Я действительно не вижу причин не использовать вложенные , если . Они очень просты в понимании и эффективны настолько, насколько вы хотите. Я бы пошёл за ними только ради их простоты.

1
ответ дан 13 December 2019 в 05:36
поделиться

Может быть, скоро вернется?

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

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

    ...

Ответ Муравья Аасмы тоже хорош. Если вы предпочитаете меньше шаблонов, вы можете написать это самостоятельно, используя подробный синтаксис регулярных выражений .

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
ответ дан 13 December 2019 в 05:36
поделиться

Возможно, это немного выходит за рамки проектирования решения, но вы можете объединить их как один регеxp с именованными группами и посмотреть, какая группа подходит. Это может быть инкапсулировано как вспомогательный класс:

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
3
ответ дан 13 December 2019 в 05:36
поделиться

Это хорошее приложение для недокументированного, но довольно полезного класса re.Scanner.

3
ответ дан 13 December 2019 в 05:36
поделиться

Вы можете использовать

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])
1
ответ дан 13 December 2019 в 05:36
поделиться

Сделайте это с помощью elif, если вам просто нужно соответствие True / False вне регулярного выражения:

if regex1.match(str):
    # do stuff
elif regex2.match(str):
    # and so on
0
ответ дан 13 December 2019 в 05:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: