1.极限压缩版
import re, functools def cal(formula): while re.search(\'(?:\d+\.?\d+|\d+)[+\-*/]\', formula): while re.search(\'[*/]\', formula): formula = re.sub(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', str(functools.reduce(lambda i, j: float(i) * float(j), re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group().split(\'*\')) if \'*\' in re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group() else functools.reduce(lambda i, j: float(i) / float(j), re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group().split(\'/\'))), formula, 1) if re.search(\'(?:\d+\.?\d+|\d+)[+\-]\', formula): formula = re.sub(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', str(functools.reduce(lambda i, j: float(i) + float(j), re.search(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group().rsplit(\'+\', 1)) if \'+\' in re.search(\'(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group() else functools.reduce(lambda i, j: float(i) - float(j), re.search(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group().rsplit(\'-\', 1))), formula, 1) return formula formula = \'1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))\' while re.search(\'\([^\(\)]+\)\', formula): formula = re.sub(\'\([^\(\)]+\)\', cal(re.search(\'\([^\(\)]+\)\', re.sub(\'\s\', \'\', formula)).group()).strip(\'()\'), formula, 1) while re.search(\'[+\-*/]-\', formula): formula = re.sub(\'[+]-\', \'-\', formula) if \'+-\' in formula else re.sub(\'--\', \'\', formula) if formula.startswith(\'--\') else re.sub(\'(?:\d+\.?\d+|\d+)[*/]-\', \'-\' + re.findall(\'(?:\d+\.?\d+|\d+)[*/](?=-)\', formula)[0], formula) if re.search(\'[*/]-\', formula) else re.sub(\'--\', \'+\', formula) print(cal(formula).split(\'.0\')[0] if cal(formula).endswith(\'.0\') else cal(formula))
2.完整版
import re from functools import reduce def plus_minus(formula): \'\'\' 计算无括号的加减法算式 :param formula: 等待计算的只包含加减法的字符串 :return: 计算结果的字符串 \'\'\' p1 = re.compile(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\') # 匹配一次加减法 while re.search(p1, formula): # 每次计算一个二元加减,并替换到原字符串上,直到计算并计算完所有数 x = re.search(p1, formula).group() # 匹配出一次计算,判断是加法还是减法,再由reduce把分割后的两个数交给匿名函数去计算。 formula = re.sub(p1, str(reduce(lambda i, j: float(i) + float(j), x.rsplit(\'+\', 1)) if \'+\' in x else reduce(lambda i, j: float(i) - float(j), x.rsplit(\'-\', 1))), formula, 1) return formula # ps.计算加减法可以采用与乘除法不同的方式,可以把所有数全匹配出来再一起计算出来 def multi_divi(formula): \'\'\' 计算无括号的乘除法算式 :param formula: 等待计算的只包含乘除法的字符串 :return: 计算结果的字符串 \'\'\' p = re.compile(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\') while re.search(p, formula): y = re.search(p, formula).group() formula = re.sub(p, str(reduce(lambda i, j: float(i) * float(j), y.split(\'*\')) if \'*\' in y else reduce(lambda i, j: float(i) / float(j), y.split(\'/\'))), formula, 1) return formula def parentheses_parse(formula): \'\'\' 用来处理括号,并调用加减乘除完成计算 :param formula: 数学算式的字符串,支持加减乘除和括号 :return: 最终结果的整型或浮点型 \'\'\' formula = re.sub(\'\s\', \'\', formula) p = re.compile(\'\([^\(\)]+\)\') # 匹配内层括号 while re.search(p, formula): # 循环到没有括号为止 f = re.search(p, formula).group() formula = re.sub(p, plus_minus(multi_divi(f)).strip(\'()\'), formula, 1) # 调用加减法嵌套乘除法,计算完括号内的式子,并去除括号 # 处理去除括号后可能出现的其他符号与负号相连的情况 while re.search(\'[+\-*/]-\', formula): formula = re.sub(\'[+]-\', \'-\', formula) formula = re.sub(\'--\', \'\', formula) if formula.startswith(\'--\') else re.sub(\'--\', \'+\', formula) # 正负为负,负负为正,并且避免正号出现在最前端 if re.search(\'[*/]-\', formula): # 遇到乘除连接负号的情况时,需要先把负号前置,再进行一次上面加减连接负号的处理 n = re.search(\'(?:\d+\.?\d+|\d+)[*/](?=-)\', formula).group() # 这里使用正向预匹配获得如\'7*-\'这样的序列中的\'7*\'的部分 formula = re.sub(\'(?:\d+\.?\d+|\d+)[*/]-\', \'-\' + n, formula) # 使用刚获得的字符串进行替换,来使‘7*-’变成‘-7*’的样子 formula = plus_minus(multi_divi(formula)) # 没有括号了,再计算最后一次 if formula.endswith(\'.0\'): # 优化显示 formula = int(formula.split(\'.0\')[0]) else: formula = float(formula) return formula # 在此处输入算式 print(parentheses_parse(\'1-2*((60- 30+(-40/5)*(9 -2*5/3+7/3*99/4*2998+1 0*568/14))-(-4*3)/(16-3*2))\'))
3.思路清晰版
import re from functools import reduce def mul_div(exp): """ 计算两个数的乘法或者除法 :param exp: :return: """ if \'*\' in exp: a, b = exp.split(\'*\') return float(a)*float(b) if \'/\' in exp: a, b = exp.split(\'/\') return float(a) / float(b) def exp_fmt(exp): """ 符号整理 :param exp: :return: """ while re.search(\'[+-]{2,}\',exp): exp = exp.replace(\'--\',\'+\') exp = exp.replace(\'+-\',\'-\') exp = exp.replace(\'-+\',\'-\') exp = exp.replace(\'++\',\'+\') return exp def remove_addsub(exp): """ 计算两个数的加减法 :param exp: :return: """ ret = re.findall(\'[-+]?\d+(?:\.\d+)?\',exp) res = reduce(lambda a,b:float(a)+float(b),ret) return res def remove_muldiv(exp): """ 计算表达式中的所有的乘除法 :param exp: :return: """ while True: ret = re.search(\'\d+(\.\d+)?[*/]-?\d+(\.\d+)?\',exp) if ret: son_exp = ret.group() res = mul_div(son_exp) exp = exp.replace(son_exp,str(res)) else:return exp def cal(exp): res = remove_muldiv(exp) # 计算乘除 res = exp_fmt(res) # 符号整理 ret = remove_addsub(res) # 计算加减 return ret def main(exp): exp = exp.replace(\' \',\'\') while True: ret = re.search(\'\([^()]+\)\', exp) if ret: res = cal(ret.group()) exp = exp.replace(ret.group(), str(res)) else: return cal(exp) exp = \'1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )\' ret = main(exp) print(ret)
待续