【问题标题】:Evaluating mathematical expressions in Python在 Python 中评估数学表达式
【发布时间】:2011-06-30 06:53:22
【问题描述】:

我想将给定的数学表达式标记为这样的解析树:

((3 + 4 - 1) * 5 + 6 * -7) / 2

                          '/'
                        /     \
                       +        2
                    /     \
                  *         *
                /   \     /   \
               -     5   6     -7
             /   \
            +     1
          /   \
         3     4

有没有任何纯 Python 方法可以做到这一点?就像作为字符串传递给 Python,然后像上面提到的那样以树的形式返回。

谢谢。

【问题讨论】:

    标签: python parsing math binary-tree mathematical-expressions


    【解决方案1】:

    有很多好的、成熟的算法可以解析像这样的数学表达式。一个特别好的是 Dijkstra 的shunting-yard algorithm,它可以用来生产这样一棵树。我不知道 Python 中的特定实现,但该算法并不是特别复杂,应该不会花费太长时间来完成一个。

    顺便说一句,您正在构建的树的更精确术语是 parse treeabstract syntax tree

    【讨论】:

      【解决方案2】:

      我不知道执行此操作的“纯 python”方式,它已经为您实现了。但是,您应该查看 ANTLR (http://www.antlr.org/),它是一个开源解析器和词法分析器,它具有适用于多种语言的 API,包括 python。此外,该网站还有一些很棒的视频教程,将向您展示如何按照您的要求进行操作。这是一个非常有用的工具,可以了解如何使用。

      【讨论】:

        【解决方案3】:

        是的,Python ast 模块提供了执行此操作的工具。您必须查找您的 Python 版本的确切接口,因为 ast 模块似乎定期更改。

        特别是,ast.parse() 方法将对您的应用程序有所帮​​助:

        >>> import ast
        >>> ast.parse("(1+2)*3", "", "eval")
        <_ast.Expression object at 0x88950>
        >>> ast.dump(_)
        'Expression(body=BinOp(left=BinOp(left=Num(n=1), op=Add(), right=Num(n=2)), op=Mult(), right=Num(n=3)))'
        

        【讨论】:

          【解决方案4】:

          有几个 Python 解析器框架;一些常见的是PLYpyparsing。 Ned Batchelder 有一个pretty complete list

          【讨论】:

          【解决方案5】:

          您可以使用 Python ast 模块来做到这一点。

          https://docs.python.org/3.6/library/ast.html

          运算是我们要评估的数学运算,我们使用 isinstance 来了解它的类型,如果它是一个数字,如果它是一个二元运算符(+,*,..)。您可以在 https://greentreesnakes.readthedocs.io/en/latest/tofrom.html 阅读 ast 的工作原理

          为了使我们可以使用的方法工作:evaluate(ast.parse(theoperation, mode='eval').body)

          def evaluate(theoperation): 
              if (isinstance(theoperation, ast.Num)):
                  return theoperation.n
              if (isinstance(theoperation, ast.BinOp)):
                  leftope= evaluate(theoperation.left)
                  rightope=evaluate(theoperation.right)   
                  if (isinstance(theoperation.op, ast.Add)):
                      return left+right
                  elif (isinstance(theoperation.op, ast.Sub)):
                      return left-right
                  elif (isinstance(theoperation.op, ast.Mult)):
                      return left*right
                  elif (isinstance(theoperation.op, ast.Div)):
                      return left/right
                  elif (isinstance(theoperation.op, ast.Pow)):
                      return left**right
          

          【讨论】:

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