如何在Python中组合switch-case和regex

时间:2022-10-30 16:08:52

I want to process a string by matching it with a sequence of regular expression. As I'm trying to avoid nested if-then, I'm thinking of switch-case. How can I write the following structure in Python? Thank you

我想通过将其与正则表达式序列进行匹配来处理字符串。因为我试图避免嵌套if-then,我正在考虑切换案例。如何在Python中编写以下结构?谢谢

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

I know Perl allows one to do that. Does Python?

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

5 个解决方案

#1


1  

You are looking for pyswitch (disclaimer: I am the author). With it, you can do the following, which is pretty close to the example you gave in your question:

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

There's a much more comprehensive example given at the URL I linked. pyswitch is not restricted to just switching on regular expressions. Internally, pyswitch uses a dispatch system similar to the examples others have given above. I just got tired of having to re-write the same code framework over and over every time I needed that kind of dispatch system, so I wrote pyswitch.

在我链接的URL上给出了一个更全面的例子。 pyswitch不仅限于打开正则表达式。在内部,pyswitch使用类似于上面其他人给出的示例的调度系统。我只是厌倦了每次需要那种调度系统时都不得不重复编写相同的代码框架,所以我写了pyswitch。

#2


8  

First consider why there is no case statement in Python. So reset you brain and forget them.

首先考虑为什么Python中没有case语句。所以重置大脑并忘记它们。

You can use an object class, function decorators or use function dictionaries to achieve the same or better results.

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

Here is a quick trivial example:

这是一个简单的例子:

#!/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 style case / switch statements also "fall through, such as:

C风格案例/开关语句也“落空”,例如:

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

Using tuples and lists of callables, you can get the similar behavior:

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

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

This gets the order for the found item correct: 1) pick up child, cuddle the child; 2) kill the rat, pick up the rat... It would be difficult to do the same with a C switch statement in an understandable syntax.

这使得找到的项目的顺序正确:1)捡起孩子,抱抱孩子; 2)杀死老鼠,拿起老鼠...用可理解的语法中的C switch语句做同样的事情是很困难的。

There are many other ways to imitate a C switch statement. Here is one (for integers) using function decorators:

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

To paraphrase Larry Wall, Tom Christiansen, Jon Orwant in Programming Perl regarding understanding context in Perl:

用Perl编写Perl中的Larry Wall,Tom Christiansen,Jon Orwant来理解Perl中的上下文:

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

在你使用语言原生的习语之前,你将是悲惨的编程Python ...

#3


2  

A quick search shows a similar question asked earlier with multiple work arounds. May favorite solution from that one is by Mizard

快速搜索显示了一个类似的问题,前面提到了多个解决方案。可能最喜欢的解决方案是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

#4


2  

Your question regarding Perl style switch statements is ambiguous. You reference Perl but you are using a C style switch statement in your example. (There is a deprecated module that provides C style switch statements in Perl, but this is not recommended...)

关于Perl样式切换语句的问题不明确。您可以引用Perl,但在示例中使用的是C style switch语句。 (有一个不推荐使用的模块在Perl中提供C样式切换语句,但不建议这样做......)

If you mean Perl given / when type switch statements, this would not be trivial to implement in Python. You would need to implement smart matching and other non-trivial Perl idioms. You might as well just write whatever in Perl?

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

If you mean C style switch statements, these are relatively trivial in comparison. Most recommend using a dictionary dispatch method, such as:

如果你的意思是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

#5


0  

If you're avoiding if-then, you can build on something like this:

如果你正在避免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()

Results

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

#1


1  

You are looking for pyswitch (disclaimer: I am the author). With it, you can do the following, which is pretty close to the example you gave in your question:

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

There's a much more comprehensive example given at the URL I linked. pyswitch is not restricted to just switching on regular expressions. Internally, pyswitch uses a dispatch system similar to the examples others have given above. I just got tired of having to re-write the same code framework over and over every time I needed that kind of dispatch system, so I wrote pyswitch.

在我链接的URL上给出了一个更全面的例子。 pyswitch不仅限于打开正则表达式。在内部,pyswitch使用类似于上面其他人给出的示例的调度系统。我只是厌倦了每次需要那种调度系统时都不得不重复编写相同的代码框架,所以我写了pyswitch。

#2


8  

First consider why there is no case statement in Python. So reset you brain and forget them.

首先考虑为什么Python中没有case语句。所以重置大脑并忘记它们。

You can use an object class, function decorators or use function dictionaries to achieve the same or better results.

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

Here is a quick trivial example:

这是一个简单的例子:

#!/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 style case / switch statements also "fall through, such as:

C风格案例/开关语句也“落空”,例如:

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

Using tuples and lists of callables, you can get the similar behavior:

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

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

This gets the order for the found item correct: 1) pick up child, cuddle the child; 2) kill the rat, pick up the rat... It would be difficult to do the same with a C switch statement in an understandable syntax.

这使得找到的项目的顺序正确:1)捡起孩子,抱抱孩子; 2)杀死老鼠,拿起老鼠...用可理解的语法中的C switch语句做同样的事情是很困难的。

There are many other ways to imitate a C switch statement. Here is one (for integers) using function decorators:

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

To paraphrase Larry Wall, Tom Christiansen, Jon Orwant in Programming Perl regarding understanding context in Perl:

用Perl编写Perl中的Larry Wall,Tom Christiansen,Jon Orwant来理解Perl中的上下文:

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

在你使用语言原生的习语之前,你将是悲惨的编程Python ...

#3


2  

A quick search shows a similar question asked earlier with multiple work arounds. May favorite solution from that one is by Mizard

快速搜索显示了一个类似的问题,前面提到了多个解决方案。可能最喜欢的解决方案是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

#4


2  

Your question regarding Perl style switch statements is ambiguous. You reference Perl but you are using a C style switch statement in your example. (There is a deprecated module that provides C style switch statements in Perl, but this is not recommended...)

关于Perl样式切换语句的问题不明确。您可以引用Perl,但在示例中使用的是C style switch语句。 (有一个不推荐使用的模块在Perl中提供C样式切换语句,但不建议这样做......)

If you mean Perl given / when type switch statements, this would not be trivial to implement in Python. You would need to implement smart matching and other non-trivial Perl idioms. You might as well just write whatever in Perl?

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

If you mean C style switch statements, these are relatively trivial in comparison. Most recommend using a dictionary dispatch method, such as:

如果你的意思是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

#5


0  

If you're avoiding if-then, you can build on something like this:

如果你正在避免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()

Results

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