无需先转换为前缀或后缀。如果您只打算评估一次或几次,那么您可以在解析时进行。我通常使用这样的递归下降:
import re
def evalExpr(infixStr):
# precedences for infix operators
precs = {'+':0 , '-':0, '/':1, '*':1, '^':2}
# functions of operators
funcs = {
'+': (lambda a,b: a+b),
'-': (lambda a,b: a-b),
'/': (lambda a,b: a/b),
'*': (lambda a,b: a*b),
'^': (lambda a,b: a**b)
}
# divide string into tokens
tokens = re.split(r' *([\(\)\+\-\*\^/]) *', infixStr)
tokens = [t for t in tokens if t!='']
# current parse position
pos = 0
# evaluate infix expression at the parse point,
# processing only operators above a given precedence
def eval2(minprec,closer=None):
nonlocal pos, tokens
# first we need a number or parenthesized expression
if (pos >= len(tokens)):
raise Exception("Unexpected end")
if (tokens[pos]=="("):
pos += 1
val = eval2(0,")")
pos += 1
else:
val = float(tokens[pos])
pos += 1
# gather operators that consume the value
while pos < len(tokens):
op = tokens[pos]
if op == closer:
return val
prec = precs.get(op)
if prec == None:
raise Exception("operator expected. got " + op)
if prec<minprec: # precedence too low for us
break
pos += 1 # operator OK
# get the argument on the operator's right
# this will go to the end, or stop at an operator
# with precedence <= prec
arg2 = eval2(prec+1,closer)
val = (funcs[op])(val, arg2)
if closer != None:
raise Exception("Expected " + closer)
return val
return eval2(0)
print(evalExpr("5+3*4^2+1")) # prints 54.0
print(evalExpr("7+(8/2)*5")) # prints 27.0
print(evalExpr("3*5+8*7")) # prints 71.0
这种递归下降风格是写了很多表达式解析器的结果,现在我几乎总是用这种方式解析表达式。它与表达式解析器一样简单,并且可以轻松添加一元运算符和不同类型的括号,以及像赋值运算符一样从右到左关联的运算符。
秘诀是eval2的签名,它可以很容易地实现优先规则。