【问题标题】:python split and evaluatepython拆分和评估
【发布时间】:2011-06-14 01:03:25
【问题描述】:

如何将一个字符串(带后缀)拆分成带括号的字符串?我的意思是,如果用户输入 3 (3 6 *) * 我希望解释器能够乘以 3 18 * 并理解文本中的括号。这可能吗?类似于str.split(),但有一个开始和结束分隔符?

我不是很现实吗?我发现 shlex 模块类似,但它只引用 AFAIK。

【问题讨论】:

  • 关于质量标准:meta.stackexchange.com/questions/92074/…。尤其要确保使用正确的大小写。
  • 你为什么要在后缀表达式中使用括号?
  • 为什么后缀表达式需要括号?
  • 这些都是很好的问题,但我只是好奇。
  • 如果可以请回答...postfix 部分有点不相关

标签: python string split


【解决方案1】:

我不认为使用re 是个坏主意。您可以一次将嵌套括号替换为它们的操作结果。对我来说似乎很简单:

import re
regex = re.compile(r'\([^\(\)]+\)')

def eval_expr(expr):
    match = regex.search(expr)
    if match:
        sub_expr = match.group()
        return eval_expr(expr.replace(sub_expr, str(eval_expr(sub_expr[1:-1]))))
    args = expr.split()
    op = args.pop()
    return eval(op.join(args))

并像这样使用:

>>> eval_expr('(1 (2 3 -) 4 +) (5 6 *) 7 +')
<<< 41

【讨论】:

    【解决方案2】:

    我对正则表达式不是很熟悉。要求这个例子是不是太过分了?

    正如克里斯的,呃,杂色的 cmets 所指出的,你不能有一个(真正的)正则表达式来解析嵌套的括号。 (据他说,有一些技巧和扩展可以扩展表达式语言,让它解析上下文无关的语法。这是我第一次听说,但对我来说这听起来是个坏主意。 )

    这个答案似乎也有反对意见......还有其他方法可以做到这一点吗?

    阅读this

    【讨论】:

      【解决方案3】:

      您可以编写regular expression 来提取带括号的子表达式。如果您关心的是拆分匹配的括号,re.split 可能会有所帮助。一个简单的正则表达式可以让您挑选出子表达式。

      #!/usr/bin/env python
      import re
      source = r"3 (3 6 *) *"
      rewritten = source[:]
      match_index = 1
      snag_deepest = re.compile(r"""(?P<pre>.*)(?P<sub>\([^()]+\))(?P<post>.*)""")
      
      print "Starting -> %s" % (rewritten)
      results = snag_deepest.search(rewritten)
      while results is not None:
          print "Subexpression %d -> %s" % (match_index, results.group('sub'))
          rewritten = "%s%s%s" % (results.group('pre'), "sub_%d" % match_index, results.group('post'))
          print "Rewritten as -> %s" % (rewritten)
          results = snag_deepest.search(rewritten)
          match_index += 1
      

      生产

      Starting -> 3 (3 6 *) *
      Subexpression 1 -> (3 6 *)
      Rewritten as -> 3 sub_1 *
      

      【讨论】:

      • 不,你不能!我听不见你!啦啦啦啦啦啦!
      • 我对正则表达式不是很熟悉。要求这个例子是不是太过分了?
      • 我敢打赌你错了。正则表达式解析正则文法,而 OP 所描述的是(我相信)上下文无关文法。 Wikipedia 甚至说“上下文无关语法的典型例子是括号匹配。”
      • @Malvolio - 确实你是对的。现代正则表达式风格通常可以评估无congext语法,但是这样做的语法越来越复杂,许多人(比如我自己)根本不鼓励使用它。
      • @tekknolagi 您可以提取带括号的表达式,但正如@Chris Lutz 所说,这很复杂。我所做的是编写一个简单的表达式来迭代地抓取一个没有子表达式的括号表达式。写一个表达式会很讨厌。
      【解决方案4】:

      首先,了解当运算符的arity 已知时,后缀表示法中不需要括号。了解原因:

      3 3 6 * *
      

      从左边开始,堆叠操作数,直到遇到运算符:

      operands <- 3 <- 3 <- 6
      operator: *
      

      我们知道* 是一个二元运算符,因此将两个操作数从堆栈中弹出,应用该运算符,然后将结果推回:

      operands -> 3 -> 6
      operands <- 18
      

      继续累加操作数,直到遇到另一个运算符:

      operator: *
      operands -> 3 -> 18
      operands <- 54
      

      当表达式被使用时(假设它格式正确),堆栈将包含一个值:结果。

      但是您的问题是关于括号的:假设您希望能够解析任意嵌套括号,正则表达式对您没有帮助,原因解释here。您需要可以识别context free grammar 的东西,即pushdown automaton

      但我认为,您正在寻找的不仅仅是抽象的计算机科学语言; here 是一个相关问题,其中包含有关 Shunting Yard Algorithm 的一些有用信息,它将带括号的中缀表达式转换为后缀表达式。

      编辑:好的,我应该说“true 正则表达式单独 对你没有帮助。”您可以使用正则表达式(匹配最里面的括号对)和替换(实际上)将带括号的表达式视为其自己的隐式解析树。但是调车场算法更酷:)

      【讨论】:

        【解决方案5】:

        如果我错了,请纠正我,但你的表达是 RPD。如果是这样,则实际上不需要使用括号。请在下面找到我的示例(未优化且奇怪):

        import operator
        
        def rpd_eval(expression):
            if expression.count('(') != expression.count(')'):
                return 0    
            expression = expression.replace(' ', '')
            ops = {'*': operator.mul, '**': operator.pow, '%': operator.mod,
                   '+': operator.add, '-': operator.sub, '/': operator.div,
                   '^': operator.pow}        
            res = []
            for v in list(expression):
                if not v in ops and v not in ['(',')']:
                    res.append(int(v))
                elif v not in ['(',')']:
                    b = float(res.pop())
                    a = float(res.pop())
                    res.append(ops[v](a, b))
            return res[0]
        
        print rpd_eval('3(63*)*5+') # will print 59
        

        【讨论】:

          猜你喜欢
          • 2014-09-05
          • 2021-04-08
          • 1970-01-01
          • 2017-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多