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)
待續
