【问题标题】:Regular expressions related, switch-statement emulation in python正则表达式相关,python 中的 switch 语句模拟
【发布时间】:2018-02-08 16:58:22
【问题描述】:

期望的结果:

我想要一个解析器函数,它接受一串“指令”。

此字符串将使用string.split(";") 切碎并去除空格。我想检查每个“印章”是否与一堆(10+)正则表达式匹配。每个表达式还具有捕获组定义的值,我稍后将使用这些值“执行命令”。

问题:

我目前有一个长而复杂的 if、elseif、else 语句,这是非常不可取的,因为它使我的代码更难管理,也更难被其他人阅读。

目前的想法:

基本上,我想使用字典来模拟 switch 语句。但是我对正则表达式的经验很少,我能够做出正确的“表达式”来捕捉我想要的“指令”。但是我对pythons正则表达式包的工作原理非常陌生。

朝着正确方向迈出的一步已经是一个函数,在给定一个字符串和一个列表或正则表达式的字典的情况下,该函数将返回匹配的正则表达式。

示例代码:(请原谅缩进:))

class PreparedConstraintsCollection(ConstraintsCollectionABC):

not_pattern = re.compile("^not([-+]*[0-9]+)$")
ex_pattern = re.compile("^ex([-+]*[0-9]+)$")
more_pattern = re.compile("^>([-+]*[0-9]+)$")
less_pattern = re.compile("^<([-+]*[0-9]+)$")
interval_pattern = re.compile("^([-+]*[0-9]+)<x<([-+]*[0-9]+)$")

def parse_constraints_string(self, restriction_string: str) -> set:
    """
    The overly-complex function to parse the restriction control sequence strings

    Control Sequence        Meaning                     Explanation
    ---------------------------------------------------------------------------------------------
    +                       Positive only               Allow only positive values
    -                       Negative only               Allow only negative values
    notX                    Not X value                 Do not allow values X
    exX                     Must be X                   Only allow values X
    >X                      More then X                 Values must be more then X
    <X                      Less then X                 Values must be less then X
    M<x<N                   Interval M, N               Must be more then M but less then N

    :param restriction_string: a string with control sequences
    :return: return the gathered restriction instances, conserve only unique
    """
    gathered_constraints = set()

    for control_seq in restriction_string.split(";"):
        stripped = control_seq.strip().replace(" ", "")

        if stripped == "":
            continue

        elif stripped == "+":
            gathered_constraints.add(res_gallery.PositiveConstraint())

        elif stripped == "-":
            gathered_constraints.add(res_gallery.NegativeConstraint())

        elif self.not_pattern.match(stripped):

            searched = re.search(self.not_pattern, stripped)
            param = float(searched.group(1))
            gathered_constraints.add(res_gallery.NotExactValueConstraint(param))

        elif self.ex_pattern.match(stripped):

            searched = re.search(self.ex_pattern, stripped)
            param = float(searched.group(1))
            gathered_constraints.add(res_gallery.ExactValueConstraint(param))

        elif self.more_pattern.match(stripped):

            searched = re.search(self.more_pattern, stripped)
            param = float(searched.group(1))
            gathered_constraints.add(res_gallery.GreaterThanConstraint(param))

        elif self.less_pattern.match(stripped):

            searched = re.search(self.less_pattern, stripped)
            param = float(searched.group(1))
            gathered_constraints.add(res_gallery.LessThanConstraint(param))

        elif self.interval_pattern.match(stripped):

            searched = re.search(self.interval_pattern, stripped)
            param1, param2 = float(searched.group(1)), float(searched.group(2))
            gathered_constraints.add(res_gallery.IntervalConstraint(param1, param2))

        else:
            raise ValueError("Restriction string could not be parsed!")

    return gathered_constraints

【问题讨论】:

  • 如果您发布一些示例代码及其预期输出,可能会更容易为您提供帮助。感谢您对问题的详细描述!很少有新用户像您一样在他们的问题上投入如此多的精力。简洁明了:)
  • 贴代码,谢谢!

标签: python regex python-3.x switch-statement


【解决方案1】:

您的解析器的一种可能性是编写一个标记器,它将创建一个包含所有语句和找到的类型的嵌套列表:

第一步是创建语法并标记输入字符串:

import re
import collections
token = collections.namedtuple('token', ['type', 'value'])
grammar = r'\+|\-|\bnot\b|\bex\b|\>|\<|[a-zA-Z0-9_]+'
tokens = {'plus':'\+', 'minus':'\-', 'not':r'\bnot\b', 'ex':r'\bex\b', 'lt':'\<', 'gt':'\>', 'var':'[a-zA-Z0-9_]+'}
sample_input = 'val1+val23; val1 < val3 < new_variable; ex val3;not secondvar;'
tokenized_grammar = [token([a for a, b in tokens.items() if re.findall(b, i)][0], i) for i in re.findall(grammar, sample_input)]

现在,tokenized_grammar 存储了文本中所有标记化语法出现的列表:

[token(type='var', value='val1'), token(type='plus', value='+'), token(type='var', value='val23'), token(type='var', value='val1'), token(type='lt', value='<'), token(type='var', value='val3'), token(type='lt', value='<'), token(type='var', value='new_variable'), token(type='var', value='ex'), token(type='var', value='val3'), token(type='var', value='not'), token(type='var', value='secondvar')]

令牌类型和值可以作为对象访问:

full_types = [(i.type, i.value) for i in tokenized_grammar]

输出:

[('var', 'val1'), ('plus', '+'), ('var', 'val23'), ('var', 'val1'), ('lt', '<'), ('var', 'val3'), ('lt', '<'), ('var', 'new_variable'), ('var', 'ex'), ('var', 'val3'), ('var', 'not'), ('var', 'secondvar')]

要实现switch-case语句的流程,你可以创建一个字典,每个key是token的类型,value是一个类来存储对应的值和要添加的方法稍后:

class Plus:
   def __init__(self, storing):
     self.storing = storing
   def __repr__(self):
     return "{}({})".format(self.__class__.__name__, self.storing)
class Minus:
   def __init__(self, storing):
     self.storing = storing
   def __repr__(self):
     return "{}({})".format(self.__class__.__name__, self.storing)
...

然后,创建字典:

tokens_objects = {'plus':Plus, 'minus':Minus, 'not':Not, 'ex':Ex, 'lt':Lt, 'gt':Lt, 'var':Variable}

然后,您可以遍历tokenized_grammar,并为每个出现创建一个类对象:

for t in tokenized_grammar:
   t_obj = token_objects[t.type](t.value)

【讨论】:

  • 这看起来很棒,谢谢。因此,如果理解正确,语法定义了所有捕获组,避免了切碎的需要,捕获所有实例。然后,令牌字典定义“捕获组”,并从之前捕获的组中提取这些值,将它们放入字典中,令牌类型是代表值,创建类型列表和捕获值。从那时起,这似乎很棒,我可以用键实现第二个字典,因为 token.types 和值可以是对值进行操作的 lambda。对吗?
  • @SirSteel 是正确的。正则表达式抓取所有定义的标记,然后存储它们。您可以使用 lambda,但是,我建议使用字典来存储令牌类型名称并为每个令牌类型存储一个类。通过使用类,您可以创建其他方法,这些方法可以由for 循环中的对象实例快速调用。请参阅我最近的编辑。我实现了上述技术。
  • 不错!非常感谢! :)
猜你喜欢
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 2019-11-28
  • 2023-01-12
相关资源
最近更新 更多