总体思想如下:
- 将运算符合操作数分开,原理为操作符之前为操作数。
- 将中缀表达式转换为后缀表达式,并在转化的过程中直接求值。
- 具体细节代码中有注释,如果有什么不明白的地方可以私信,如有bug欢迎改正。
# 擦作数的优先级1>2,任意定义即可
ops_rule = {
'+': 1,
'-': 1,
'*': 2,
'/': 2
}
def cal(n1, n2, op):
if op == '+':
return n1 + n2
if op == '-':
return n1 - n2
if op == '*':
return n1 * n2
if op == '/':
return n1 / n2
def stringToFloat(string):
# print(string)
return float(string)
# # 字符串计算
# string = '2+3.1*4-8.2/2'
string = '((9+(3*(4-2))*((3+10)/2)))'
stackValue = []
stackOp = []
# 拆分字符串
start = 0 # 用于记录操作数起始位置
fuHao = ['+', '-', '*', '/', '(', ')']
for i, elem in enumerate(string):
if elem in fuHao:
# 操作数压栈
if len(string[start:i]) != 0: # 防止括号和操作数相邻导致操作数起始位置错误
stackValue.append(stringToFloat(string[start:i]))
# print(stackValue, stackOp)
start = i + 1
if elem == '(':
start = i + 1
stackOp.append(elem)
elif elem == ')': # 运算符一直出栈
start = i + 1
# 如果当前操作符为')'则将操作符一直出栈直到stackOp为空或者遇到'('为止。
while True:
op = stackOp[-1]
if op == '(': # 遇到'('停止出栈
stackOp.pop()
break
else:
# 操作符出栈,先出栈为右操作数
stackOp.pop()
n2 = stackValue.pop()
n1 = stackValue.pop()
result = cal(n1, n2, op)
stackValue.append(result)
# stackOp.append(elem)
# 如果为'+', '-', '*', '/'则遵循将比当前操作数(elem)优先级大的或者相等的操作数(op)出栈即op>=elem,直到stackOp空或者遇到'('为止。
else:
while len(stackOp) > 0:
op = stackOp[-1] # 访问之前的的操作数
# 如果遇到'('停止出栈
if op == '(':
break
# 将比当前操作数(elem)优先级大的或者相等的操作数(op)出栈即op>=elem
if ops_rule[elem] > ops_rule[op]:
break
else:
op = stackOp.pop()
n2 = stackValue.pop()
n1 = stackValue.pop()
result = cal(n1, n2, op)
stackValue.append(result)
stackOp.append(elem)
# 将最后的数字压入stackValue栈中,不用空格隔开这个地方就不好弄
if len(string[start:-1]) != 0:
if string[-1] == ')':
stackValue.append(stringToFloat(string[start:-1]))
else:
if len(string[start:]) != 0:
stackValue.append(stringToFloat(string[start:]))
# print(stackValue)
# print(stackOp)
# 运算符全部出栈
while len(stackOp) > 0:
op = stackOp.pop()
if op == '(':
continue
n2 = stackValue.pop()
n1 = stackValue.pop()
result = cal(n1, n2, op)
stackValue.append(result)
# 打印结果
print(stackValue[0])