【问题标题】:how can I combine a switch-case and regex in Python如何在 Python 中组合 switch-case 和正则表达式
【发布时间】:2011-02-12 19:35:07
【问题描述】:

我想通过将字符串与一系列正则表达式进行匹配来处理它。当我试图避免嵌套的 if-then 时,我正在考虑 switch-case。如何在 Python 中编写以下结构?谢谢

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

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

【问题讨论】:

  • 这在 Perl 中是不合法的语法。你的意思是given / when 语法吗?
  • @drewk:是的,这就是我想要的。

标签: python switch-statement


【解决方案1】:

首先考虑why there is no case statement in Python。所以重置你的大脑并忘记它们。

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

这是一个简单的简单示例:

#!/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()

Programming Perl 中关于理解 Perl 上下文的 Larry Wall、Tom Christiansen、Jon Orwant 的解释:

除非你使用语言原生的习语,否则你会很痛苦地编写 Python...

【讨论】:

  • 这比 C/Perl 切换更加冗长和烦人!
  • 一开始可能会,但你习惯了。
  • 自 2007 年以来我一直在编写 python,但我仍然认为它很烂。
【解决方案2】:

快速搜索显示之前询问过的similar question 有多种解决方法。可能最喜欢的解决方案是 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

【讨论】:

  • 谢谢!但我避免使用 if-then。
【解决方案3】:

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

如果您的意思是 Perl given / when type switch statements,那么在 Python 中实现这一点并非易事。您需要实现smart matching 和其他重要的Perl 习惯用法。还是直接用 Perl 写吧?

如果您的意思是C style switch statements,相比之下,这些相对微不足道。大多数建议使用字典调度方法,例如:

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

【讨论】:

  • 我将在这里使用 lambdas 来使 case 的表达更具声明性。感谢您的启发!
【解决方案4】:

您正在寻找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。

【讨论】:

    【解决方案5】:

    如果您要避免 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.'
    

    【讨论】:

      【解决方案6】:

      Python 3.10 现在支持匹配大小写。但是不能在语句中使用正则表达式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-01-12
        • 1970-01-01
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多