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

发布于 2024-10-17 01:30:44 字数 247 浏览 3 评论 0 原文

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

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

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

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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

如日中天 2024-10-24 01:30:44

首先考虑为什么有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 语句。一个(对于整数)使用函数装饰器:

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 编程将会很痛苦......

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

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:

   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.

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

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:

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

誰認得朕 2024-10-24 01:30:44

快速搜索显示了一个类似问题早些时候有多种解决方法。 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

A quick search shows a similar question asked earlier with multiple work arounds. May favorite solution from that one is by 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
呆° 2024-10-24 01:30:44

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

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:

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.

云裳 2024-10-24 01:30:44

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

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

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.'
凡尘雨 2024-10-24 01:30:44

Python 从 3.10 版本开始支持 switch 语句。下面是一个使用正则表达式和 Python 的新 switch 语句语法的示例:

match = re.match(r"(?P<time>\d+)(?P<unit>[a-zA-Z]{1,2})", duration_string)
time = int(match.group("time"))
unit = match.group("unit")

match unit:
    case "us":
        return timedelta(microseconds=time)
    case "ms":
        return timedelta(milliseconds=time)
    case "s":
        return timedelta(seconds=time)
    case "m":
        return timedelta(minutes=time)
    case "h":
        return timedelta(hours=time)
    case "d":
        return timedelta(days=time)
    case "w":
        return timedelta(weeks=time)
    case _:
        raise TypeError("Unsupported time duration.")

这将采用一个包含数字和时间单位的字符串,例如“15d”是 15 天。正则表达式将 15 和 d 分开,然后对这些单位执行 switch 语句。

此代码转换 Polar 的样式持续时间格式(更多信息此处)到 timedelta 格式。

当然,您可以将任何类型的正则表达式与这样的 switch 语句一起使用。我推荐命名组,因为它使阅读代码更容易。

Python since version 3.10 supports switch statements. Here's an example using regex with Python's new switch statement synax:

match = re.match(r"(?P<time>\d+)(?P<unit>[a-zA-Z]{1,2})", duration_string)
time = int(match.group("time"))
unit = match.group("unit")

match unit:
    case "us":
        return timedelta(microseconds=time)
    case "ms":
        return timedelta(milliseconds=time)
    case "s":
        return timedelta(seconds=time)
    case "m":
        return timedelta(minutes=time)
    case "h":
        return timedelta(hours=time)
    case "d":
        return timedelta(days=time)
    case "w":
        return timedelta(weeks=time)
    case _:
        raise TypeError("Unsupported time duration.")

This will take a string with a number and a time unit in it, e.g. "15d" is 15 days. The regex splits the 15 and the d up, then a switch statement is performed on the units.

This code converts Polar's style time duration format (further information here) to the timedelta format.

Of course you can use any kind of regex with a switch statement like this. I recommend named groups, as it makes reading the code easier.

不打扰别人 2024-10-24 01:30:44

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

如果您指的是 Perl 给定 / 当输入 switch 语句时,这在 Python 中实现起来并不容易。您需要实现智能匹配和其他重要的Perl习语。你还不如用 Perl 写任何东西?

如果您指的是 C 样式 switch 语句,那么相比之下,这些相对琐碎。大多数建议使用字典调度方法,例如:

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

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...)

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?

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文