как я могу объединить switch-case и regex в Python - PullRequest
5 голосов
/ 12 февраля 2011

Я хочу обработать строку, сопоставив ее с последовательностью регулярного выражения. Поскольку я пытаюсь избежать вложенного if-then, я думаю о switch-case. Как я могу написать следующую структуру в Python? Спасибо

switch str:
   case match(regex1):
       # do something
   case match(regex2):
       # do sth else

Я знаю, что Perl позволяет это делать. Есть ли Python?

Ответы [ 5 ]

8 голосов
/ 13 февраля 2011

Сначала рассмотрим , почему в Python нет оператора case . Так что перезагрузите свой мозг и забудьте о них.

Вы можете использовать класс объектов, декораторы функций или словари функций для достижения тех же или лучших результатов.

Вот простой пример:

#!/usr/bin/env python
import re

def hat(found):
    if found: print "found a hat"
    else: print "no hat"

def cat(found):
    if found: print "found a cat"
    else: print "no cat"

def dog(found):    
    if found: print "found a dog"
    else: print "no dog"

st="""
Here is the target string
with a hat and a cat
no d o g 
end
"""

patterns=['hat', 'cat', 'dog']
functions=[hat,cat,dog]

for pattern,case in zip(patterns,functions):
    print "pattern=",pattern
    case(re.search(pattern,st))

Операторы case / switch в стиле C также "проваливаются", такие как:

   switch(c) {
       case 'a':
       case 'b':
       case 'c':  do_abc();
                  break;
       ... other cases...
   }

Используя кортежи и списки вызываемых объектов, вы можете получить похожее поведение:

st="rat kitten snake puppy bug child"

def proc1(st): print "cuddle the %s" % st
def proc2(st): print "kill the %s" % st
def proc3(st): print "pick-up the %s" % st
def proc4(st): print "wear the %s" % st
def proc5(st): print "dispose of the %s" %st
def default(st): print "%s not found" % st

dproc={ ('puppy','kitten','child'): 
            [proc3, proc1], 
        ('hat','gloves'): 
            [proc3, proc4], 
        ('rat','snake','bug'): 
            [proc2, proc3, proc5]}

for patterns,cases in dproc.iteritems():
    for pattern in patterns:
        if re.search(pattern,st):
            for case in cases: case(pattern)
        else: default(pattern)    
        print

Получается правильный порядок для найденного предмета: 1) забрать ребенка, обнять ребенка; 2) убить крысу, поднять крысу ... Было бы трудно сделать то же самое с оператором C в понятном синтаксисе.

Есть много других способов имитировать оператор C switch. Вот один (для целых чисел), использующий декораторы функций:

case = {}

def switch_on(*values):
    def case_func(f):
        case.update((v, f) for v in values)
        return f
    return case_func

@switch_on(0, 3, 5)
def case_a(): print "case A"

@switch_on(1,2,4)
def case_b(): print "case B"

def default(): print "default"

for i in (0,2,3,5,22):
    print "Case: %i" % i
    try: 
        case[i]()
    except KeyError:
        default()

Перефразируя Ларри Уолла, Тома Кристиансена, Джона Орванта в Программирование на Perl относительно понимания контекста в Perl:

Вы будете жалким программистом на Python, пока не будете использовать идиомы, родные для языка ...

3 голосов
/ 12 февраля 2011

Быстрый поиск показывает аналогичный вопрос , заданный ранее с несколькими обходными путями. Пусть любимое решение от этого - Mizard

import re

class Re(object):
  def __init__(self):
    self.last_match = None
  def match(self,pattern,text):
    self.last_match = re.match(pattern,text)
    return self.last_match
  def search(self,pattern,text):
    self.last_match = re.search(pattern,text)
    return self.last_match

gre = Re()
if gre.match(r'foo',text):
  # do something with gre.last_match
elif gre.match(r'bar',text):
  # do something with gre.last_match
else:
  # do something else
2 голосов
/ 13 февраля 2011

Ваш вопрос относительно операторов переключения в стиле Perl неоднозначен. Вы ссылаетесь на Perl, но в своем примере вы используете оператор переключения стиля C. (Существует устаревший модуль, который предоставляет операторы переключения в стиле C в Perl, но это не рекомендуется ...)

Если вы имеете в виду Perl заданные / когда операторы переключения типов , это не будет тривиальным для реализации в Python. Вам нужно будет реализовать интеллектуальное сопоставление и другие нетривиальные идиомы Perl. С таким же успехом можно написать что-нибудь на Perl?

Если вы имеете в виду операторы переключения в стиле C , это сравнительно тривиально по сравнению. Большинство рекомендуют использовать метод отправки словаря, такой как:

import re

def case_1():
    print "case 1"
    return 1

def case_2():
    print "case 2"
    return 2

def case_3():
    print "case 3"
    return 3

def default():
    print "None"
    return 0

dispatch=   {  
            'a':            case_1, 
            'g':            case_2, 
            'some_other':   case_3,
            'default':      default
            }

str="abcdefg"

r=[dispatch[x]() if re.search(x,str) else dispatch['default']() 
             for x in ['a','g','z'] ]

print "r=",r
1 голос
/ 13 февраля 2011

Вы ищете pyswitch (отказ от ответственности: я автор). С его помощью вы можете сделать следующее, что очень близко к примеру, который вы дали в своем вопросе:

from pyswitch import Switch

mySwitch = Switch()

@myswitch.caseRegEx(regex1)
def doSomething(matchObj, *args, **kwargs):
    # Do Something
    return 1

@myswitch.caseRegEx(regex2)
def doSomethingElse(matchObj, *args, **kwargs):
    # Do Something Else
    return 2

rval = myswitch(stringYouWantToSwitchOn)

Существует гораздо более полный пример, приведенный по URL-адресу, на который я ссылаюсь. Pyswitch не ограничивается простым включением регулярных выражений. Внутри Pyswitch использует систему диспетчеризации, аналогичную приведенным выше примерам. Мне просто надоело переписывать одну и ту же структуру кода снова и снова каждый раз, когда мне понадобилась такая система диспетчеризации, поэтому я написал pyswitch.

0 голосов
/ 13 февраля 2011

Если вы избегаете if-then, вы можете построить что-то вроде этого:

import re

# The patterns
r1 = "spam"
r2 = "eggs"
r3 = "fish"

def doSomething1():
    return "Matched spam."

def doSomething2():
    return "Matched eggs."

def doSomething3():
    return "Matched fish."

def default():
    return "No match."

def match(r, s):
    mo = re.match(r, s)
    try:
        return mo.group()
    except AttributeError:
        return None

def delegate(s):
    try:
        action = {
            match(r1, s): doSomething1,
            match(r2, s): doSomething2,
            match(r3, s): doSomething3,
        }[s]()
        return action
    except KeyError:
        return default()

Результаты

>>> delegate("CantBeFound")
0: 'No match.'
>>> delegate("spam")
1: 'Matched spam.'
>>> delegate("eggs")
2: 'Matched eggs.'
>>> delegate("fish")
3: 'Matched fish.'
...