Оценка математических выражений в Python
Я хочу, чтобы токенизировать заданное математическое выражение в дереве синтаксиса следующим образом:
((3 + 4 - 1) * 5 + 6 * -7) / 2
'/'
/ \
+ 2
/ \
* *
/ \ / \
- 5 6 -7
/ \
+ 1
/ \
3 4
Есть ли какой-нибудь чистый способ Python для этого? Как передача строки в Python, а затем возврат в виде дерева, как указано выше.
Спасибо.
Ответы
Ответ 1
Да, модуль 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)))'
Ответ 2
Для Python существует несколько систем парсера; некоторые общие PLY и pyparsing. Ned Batchelder имеет довольно полный список.
Ответ 3
Существует много хороших, установленных алгоритмов для синтаксического анализа математических выражений, подобных этому. Одним из особенно хороших является Dijkstra алгоритм шунтирования, который можно использовать для создания такого дерева. Я не знаю конкретной реализации на Python, но алгоритм не является особенно сложным, и не стоит слишком долго бить его.
Кстати, более точный термин для дерева, которое вы строите, это дерево или абстрактное синтаксическое дерево.
Ответ 4
Я не знаю способ "чистого питона", который уже реализован для вас. Однако вы должны проверить ANTLR (http://www.antlr.org/) это парсер с открытым исходным кодом lexer, и он имеет API для нескольких языков, включая python. Также на этом веб-сайте есть отличные видеоуроки, которые покажут вам, как делать именно то, что вы просите. Это очень полезный инструмент, чтобы знать, как использовать в целом.
Ответ 5
Вы можете сделать это с помощью модуля Python ast.
https://docs.python.org/3.6/library/ast.html
theoperation - наша математическая операция, которую мы хотим оценить, мы используем isinstance для того, чтобы знать тип, который он есть, если его число, если это бинарный оператор (+, *,..). Вы можете читать https://greentreesnakes.readthedocs.io/en/latest/tofrom.html, как работает ast
И для того, чтобы этот метод работал, мы можем использовать: оценить (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