Оценка математических выражений в Python - PullRequest
11 голосов
/ 19 февраля 2011

Я хочу разбить данное математическое выражение на дерево разбора, например:

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

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

Есть ли какой-нибудь чистый способ Python для этого?Как передача в Python в виде строки, а затем возврат в виде дерева, как упомянуто выше.

Спасибо.

Ответы [ 5 ]

9 голосов
/ 19 февраля 2011

Да, модуль 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)))'
3 голосов
/ 19 февраля 2011

Для Python существует несколько каркасов парсера;Некоторые из них: PLY и pyparsing .Нед Бэтчелдер имеет довольно полный список .

1 голос
/ 16 июня 2016

Вы можете сделать это с помощью модуля Python ast.

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

theoperation - наша математическая операция, которую мы хотим оценить, мы используем isinstance, чтобы узнать, какой это тип, если это число, если это бинарный оператор (+, *, ..). Вы можете прочитать на https://greentreesnakes.readthedocs.io/en/latest/tofrom.html, как работает АСТ

И для того, чтобы метод работал, мы должны использовать: define (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
1 голос
/ 19 февраля 2011

Есть много хороших, установленных алгоритмов для синтаксического анализа математических выражений, подобных этому.Один особенно удачный пример - алгоритм Дейкстры shunting-yard , который можно использовать для создания такого дерева.Я не знаю какой-либо конкретной реализации в Python, но алгоритм не особенно сложен, и для его взлома не потребуется слишком много времени.создаем дерево разбора или абстрактное синтаксическое дерево .

0 голосов
/ 19 февраля 2011

Я не знаю способа «чистого питона», который уже реализован для вас.Однако вы должны проверить ANTLR (http://www.antlr.org/) это парсер с открытым исходным кодом, лексер и имеет API для ряда языков, включая python. Также на этом сайте есть несколько отличных видеоуроков, которые покажут вам, как делать именно то, что вы естьспрашивать. Это очень полезный инструмент, чтобы знать, как использовать в целом.

...