先来谈谈这个项目的初衷:目标是实现一个类似于Python内置eval函数的功能,能够处理包含括号、加减乘除的复杂算术表达式,从而提供一个简洁的计算器工具。当然,这里不涉及安全性和性能的考虑,纯粹是为了练习递归算法和数据处理技巧。
整体思路非常清晰,核心可以分为三个步骤:首先,利用正则表达式将原始字符串拆分成列表,方便逐项处理——将数字、运算符和括号分别提取出来。其次,采用递归方式逐步去除最内层的括号,一层层向外剥离,直到整个表达式不再包含括号。这一步需要妥善处理符号粘连的问题,例如- -或 -等情况。最后,在没有括号的表达式上,先进行乘除运算,再进行加减运算,最终得到计算结果。
关键难点在于括号的剥离方式。不能简单使用index()来查找左括号,因为index总是返回第一个匹配项,而不是当前遇到的那个。因此需要自行维护一个计数器count,在遍历列表时记录左括号的索引,直到遇到第一个右括号,然后切片取出中间部分,计算后替换回原列表中的相应位置。每次替换后触发递归,直至所有括号被消除。
替换后很可能出现-或- -这类多余的符号,因此需要专门编写一个change()函数来处理:检测到连续两个减号时合并成一个加号(正负抵消),类似地处理空格与加减号并存的情况。这个函数在递归过程中以及乘除运算后都需要调用。
乘除运算同样采用递归思路:从左到右遍历列表,遇到*或/时就计算相邻的两个数,然后用结果替换左操作数,删除操作符和右操作数,接着递归调用自身,直到没有乘除符号。需要注意操作数为负数(即* -形式)时的符号处理。
加减运算相对简单,直接遍历列表累加即可,但需注意第一个元素可能是负号。最终根据结果的正负返回不同格式的列表(正数直接返回字符串,负数则返回['-', str(-sum)]形式)。
整个流程通过calculate()函数判断是否包含乘除或加减运算,自动调用对应的处理函数;而simplify()函数负责递归剥除括号;最终calculator()主函数完成字符串格式化、去括号、计算并返回浮点数结果。
以下是完整代码实现,请注意正则表达式拆分时的细节以及符号处理中的边界情况:
import re
def eq_format(eq):
'''
将算术字符串拆分为列表,例如 '1-2*3' -> ['1','-','2','*','3']
'''
format_list = re.findall(r'[\d.]+|[()+\-*/]', eq)
return format_list
def change(eq, count):
'''
处理列表中连续出现的 '-', '- -' 等符号问题
比如 ['-', '-', '2'] -> ['+', '2']
'''
if eq[count] == '-':
if eq[count-1] == '-':
eq[count-1] = '+'
del eq[count]
elif eq[count-1] == '+':
eq[count-1] = '-'
del eq[count]
return eq
def deal_multiplication_division(eq):
'''
递归处理所有乘除运算
'''
count = 0
while count < len(eq):
if eq[count] == '*':
if eq[count+1] != '-':
eq[count-1] = float(eq[count-1]) * float(eq[count+1])
del eq[count]
del eq[count]
else:
eq[count] = float(eq[count-1]) * float(eq[count+2])
eq[count-1] = '-'
del eq[count+1]
del eq[count+1]
eq = change(eq, count-1)
return deal_multiplication_division(eq)
elif eq[count] == '/':
if eq[count+1] != '-':
eq[count-1] = float(eq[count-1]) / float(eq[count+1])
del eq[count]
del eq[count]
else:
eq[count] = float(eq[count-1]) / float(eq[count+2])
eq[count-1] = '-'
del eq[count+1]
del eq[count+1]
eq = change(eq, count-1)
return deal_multiplication_division(eq)
count += 1
return eq
def deal_plus_minus(eq):
'''
处理加减运算,返回最终结果的列表形式
'''
if eq[0] != '-':
total = float(eq[0])
else:
total = 0.0
count = 0
for i in eq:
if i == '-':
total -= float(eq[count+1])
elif i == '+':
total += float(eq[count+1])
count += 1
if total >= 0:
return [str(total)]
else:
return ['-', str(-total)]
def calculate(s_eq):
'''
不带括号的列表,先乘除后加减
'''
if '*' in s_eq or '/' in s_eq:
s_eq = deal_multiplication_division(s_eq)
if '+' in s_eq or '-' in s_eq:
s_eq = deal_plus_minus(s_eq)
return s_eq
def simplify(format_list):
'''
递归去除所有括号
'''
bracket = 0
count = 0
while count < len(format_list):
if format_list[count] == '(':
bracket = count
elif format_list[count] == ')':
temp = format_list[bracket+1 : count]
new_temp = calculate(temp)
format_list = format_list[:bracket] + new_temp + format_list[count+1:]
format_list = change(format_list, bracket)
return simplify(format_list)
count += 1
return format_list
def calculator(eq):
format_list = eq_format(eq)
s_eq = simplify(format_list)
ans = calculate(s_eq)
if len(ans) == 2:
return -float(ans[1])
else:
return float(ans[0])
if __name__ == '__main__':
equation = '1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
ans = calculator(equation)
print('eval运算结果:', eval(equation))
print('程序运算结果:', ans)

参考链接:
link
