如何在Python中结合switch-case和正则表达式

6 投票
5 回答
15157 浏览
提问于 2025-04-16 11:42

我想处理一个字符串,通过和一系列的正则表达式进行匹配。为了避免使用嵌套的if-then语句,我在考虑用switch-case结构。请问我该如何在Python中写出这样的结构呢?谢谢!

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

我知道Perl可以做到这一点。那Python可以吗?

5 个回答

4

快速搜索一下,发现之前有一个类似的问题,里面有很多解决办法。我最喜欢的解决方案是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
9

首先,先考虑一下为什么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))

C语言风格的case/switch语句也有“贯穿”现象,比如:

   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语言的switch语句来做到这一点,语法上会比较复杂。

还有很多其他方法可以模仿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()

借用Larry Wall、Tom Christiansen和Jon Orwant在Programming Perl中的话,关于理解Perl中的上下文:

在你使用Python的本土习惯之前,你会觉得编程Python很痛苦……

1

你可以去找一下 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)

在我提供的链接里,还有一个更详细的例子。pyswitch 不仅仅是用来处理普通的正则表达式。它内部使用了一种调度系统,跟其他人提到的例子类似。我之所以写这个工具,是因为我厌倦了每次需要这种调度系统时都要重复写同样的代码框架,所以我决定自己写一个 pyswitch。

撰写回答