如何在Python中结合使用switch-case和regex

how can I combine a switch-case and regex in Python

我想通过将字符串与正则表达式序列匹配来处理字符串。当我试图避免嵌套if-then时,我想到的是切换情况。如何在Python中编写以下结构?谢谢

1
2
3
4
5
switch str:
   case match(regex1):
       # do something
   case match(regex2):
       # do sth else

我知道Perl允许这样做。是Python吗?


首先考虑为什么Python中没有case语句。因此,请重新设置您的大脑,并忘记它们。

您可以使用对象类,函数修饰符或使用函数字典来获得相同或更好的结果。

这是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/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语句也"掉进去了",例如:

1
2
3
4
5
6
7
   switch(c) {
       case 'a':
       case 'b':
       case 'c':  do_abc();
                  break;
       ... other cases...
   }

使用元组和可调用对象列表,您可以获得类似的行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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语句。这是一个使用函数修饰符的(整数):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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在《 Perl编程》中有关理解Perl中的上下文的信息:

You will be miserable programming Python until you use the idioms that are native to the language...


快速搜索显示了一个类似的问题,该问题先前已被解决,但存在多种解决方法。可能最喜欢的解决方案是Mizard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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


您有关Perl样式转换语句的问题是模棱两可的。您引用了Perl,但是在示例中使用的是C风格的switch语句。 (有一个不推荐使用的模块在Perl中提供了C风格的switch语句,但是不建议这样做...)

如果您的意思是在类型切换语句时给Perl /,那么在Python中实现将不是一件容易的事。您将需要实现智能匹配和其他不平凡的Perl习惯用法。您还可以在Perl中编写任何内容吗?

如果您指的是C风格的switch语句,则相比而言,它们相对来说是微不足道的。最推荐使用字典分派方法,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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


您正在寻找pyswitch(免责声明:我是作者)。使用它,您可以执行以下操作,这与您在问题中给出的示例非常接近:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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。


如果要避免使用if-then,则可以基于以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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()

结果

1
2
3
4
5
6
7
8
>>> delegate("CantBeFound")
0: 'No match.'
>>> delegate("spam")
1: 'Matched spam.'
>>> delegate("eggs")
2: 'Matched eggs.'
>>> delegate("fish")
3: 'Matched fish.'