計算器的思路主要是先用正則匹配出括號內的計算,而後用計算的結果將括號及內容整個替換掉,再匹配括號進行計算,替換,直至將括號內的計算所有完成ide
再者就是須要用正則匹配出乘除法先進行計算,再用正則匹配加減法進行計算,同時須要注意空格及符號的處理,如:++,—,/-,*-,或是負數開頭的公式的計算函數
r"\d+(\.\d+)?/-\d+(\.\d+)?" #匹配3/-2形式的整數或小數的乘除計算 r"\d+(\.\d+)?\*-\d+(\.\d+)?" #匹配3*-2形式的整數或小數的乘除計算 r"\d+(\.\d+)?[/*]\d+(\.\d+)?" #匹配正常的整數或小數的乘除計算 r"-\d+(\.\d+)?-\d+(\.\d+)?" #匹配-3-2形式的整數或小數的加減計算 r"-\d+(\.\d+)?\+\d+(\.\d+)?" #匹配-3+2形式的整數或小數的加減計算
具體以下:優化
import re # func = "1 - 2 * ((60 - 30 + (-40 / 5) * (9 - 2 * 5 / 3 + 7 / 3 * 99 / 4 * 2998 + 10 * 568 / 14)) # - (-4 * 3) / (16 - 3 * 2))" func = " 1+2*-(-3+2)/5.6+3" func = func.replace(" ", "") print(func) print(1+2*-(-3+2)/5.6+3) # 篩選內層括號及括號內容函數 def fun_inside(a): com = re.compile(r"\([^()]+\)") bracket = com.finditer(a) for j in bracket: yield j.group() # 去空格,處理符號函數 def formatting(a): a = a.replace(" ", "") a = a.replace("++", "+") a = a.replace("--", "+") a = a.replace("+-", "-") a = a.replace("-+", "-") a = a.replace("*+", "*") a = a.replace("/+", "/") return a # 括號內的乘除法 def cal_pursue_divide(a): s = re.findall("[*/]", a) s_list = re.split("[*/]", a) res = None for index, j in enumerate(s_list): if res: if s[index - 1] == "*": res *= float(j) elif s[index - 1] == "/": res /= float(j) else: res = float(j) return res # 括號內的加減法 def cal_add_minus(a): s = re.findall("[+-]", a) s_list = re.split("[+-]", a) res = None for index, j in enumerate(s_list): if res: if s[index - 1] == "+": res += float(j) elif s[index - 1] == "-": res -= float(j) else: res = float(j) return res # 四則運算包含特殊的"-","*-","/-","-"開頭等 def cal_in_four(a): while True: if re.search(r"[/*]", a): # 先計算乘除法 a = formatting(a) if re.search(r"\d+(\.\d+)?/-\d+(\.\d+)?", a) or \ re.search(r"\d+(\.\d+)?\*-\d+(\.\d+)?", a): # 整數或小數 # 計算 3/-2 類型 if re.search(r"\d+(\.\d+)?/-\d+(\.\d+)?", a): # 整數或小數 result_high = re.search(r"\d+(\.\d+)?/-\d+(\.\d+)?", a) ret = result_high.group().replace("/-", "/") res = cal_pursue_divide(ret) a = a.replace(result_high.group(), "-" + str(res)) # 計算 3*-2 類型 elif re.search(r"\d+(\.\d+)?\*-\d+(\.\d+)?", a): # 整數或小數 result_high = re.search(r"\d+(\.\d+)?\*-\d+(\.\d+)?", a) ret = result_high.group().replace("*-", "*") res = cal_pursue_divide(ret) a = a.replace(result_high.group(), "-" + str(res)) # 正常的乘除計算 else: if re.search(r"\d+(\.\d+)?[/*]\d+(\.\d+)?", a): # 整數或小數 result_high = re.search(r"\d+(\.\d+)?[/*]\d+(\.\d+)?", a) res = cal_pursue_divide(result_high.group()) a = a.replace(result_high.group(), str(res)) # 計算加減法 elif re.search(r"[+-]", a[2:]): a = formatting(a) # 計算"-"開頭的加減法 if a[1:].startswith("-") or a.startswith("-"): # 計算 -3-2 類型 if re.search(r"-\d+(\.\d+)?-\d+(\.\d+)?", a): # 整數或小數 result_low = re.search(r"-\d+(\.\d+)?-\d+(\.\d+)?", a) ret = result_low.group()[1:] res = cal_add_minus(ret.replace("-", "+")) a = a.replace(result_low.group(), "-" + str(res)) # 計算 -3+2 類型 elif re.search(r"-\d+(\.\d+)?\+\d+(\.\d+)?", a): # 整數或小數 result_low = re.search(r"-\d+(\.\d+)?\+\d+(\.\d+)?", a) ret = result_low.group()[1:] res = cal_add_minus(ret.replace("+", "-")) a = a.replace(result_low.group(), "-" + str(res)) # 計算正常的加減法 else: if re.search(r"\d+(\.\d+)?[+-]\d+(\.\d+)?", a): # 整數或小數 result_low = re.search(r"\d+(\.\d+)?[+-]\d+(\.\d+)?", a) res = cal_add_minus(result_low.group()) a = a.replace(result_low.group(), str(res)) else: if re.search(r"\d+(\.\d+)?[+-]\d+(\.\d+)?", a): # 整數或小數 result_low = re.search(r"\d+(\.\d+)?[+-]\d+(\.\d+)?", a) res = cal_add_minus(result_low.group()) a = a.replace(result_low.group(), str(res)) return a else: return a # 計算器函數 def calculator(s): while True: if re.search(r"\(.+\)", s): ret_receive_view = fun_inside(s) for i in ret_receive_view: ret = cal_in_four(i).replace("(", "").replace(")", "") s = s.replace(i, ret) else: result = cal_in_four(s) result = formatting(result) s = formatting(result) if s.startswith("+"): return "結果是:" + s[1:] else: return "結果是:" + s sr = calculator(func) print(sr)
改進版本以下,上個版本存在的問題主要有,加減乘除的運算過程當中對負號的處理十分複雜,且邏輯混亂,在某些複雜的負數類運算中會出現運算邏輯的問題,致使計算結果出現誤差atom
下面的版本主要優化負數的四則運算,思路是不考慮負號,以[+ - * /]進行分割,將分割的結果(多是整數,或是負數)進行計算,從而避免了負號運算出現的問題spa
import re # 去空格,處理符號函數 def formatting(a): a = a.replace("++", "+") a = a.replace("--", "+") a = a.replace("+-", "-") a = a.replace("-+", "-") return a # 加減法計算 def cal_add_sub(a): # 正則匹配出 所有的正負整數和小數 # 注意此處須要用?:去掉小數的優先級 不然將出現 ['', '.3', '.3'] ret = re.findall('[+-]?\d+(?:\.\d+)?', a) sum_as = 0 # 此處的計算四路是找出所有的正負整數和小數不考慮數字的正負直接將全部數字累加 # 從而解決負數相減等問題 for i in ret: sum_as += float(i) return sum_as # 正常乘除法計算 def cal_pursue_divide(a): # 四則運算中的乘除法需從左至右計算,因此每次的計算都是兩個數之間進行的 # 因此以 *|/進行分割,進行兩個數之間的乘除運算,避免了負號的干擾 if '*' in a: i, j = a.split('*') return str(float(i) * float(j)) elif '/' in a: i, j = a.split('/') return str(float(i) / float(j)) # 乘除負數的計算 def mul_div(a): while True: # 正則匹配出 正負整數和小數之間的乘除法 ret = re.search('\d+(\.\d+)?[*/]-?\d+(\.\d+)?', a) if ret: atom_a = ret.group() # 1*-22 # 將匹配的結果用正常的乘除法則進行運算 res = cal_pursue_divide(atom_a) a = a.replace(atom_a, res) else: return a # 四則運算 def cal_in_four(a): # 先進性乘除法的運算 a = mul_div(a) # 乘除運算完成後會出現- -或+ -等狀況須要進行符號的格式化 a = formatting(a) # 格式化完成進行加減運算 a_sum = cal_add_sub(a) return a_sum # 篩選內層括號及括號內容函數 def fun_inside(a): com = re.compile(r"\([^()]+\)") bracket = com.finditer(a) for j in bracket: # 用生成器方便下面對括號的逐個運算 yield j.group() # 計算器的主函數 def calculator(s): # 對輸入的算式去空格 s = s.replace(" ", "") while True: # 匹配到括號就進行循環去括號 if re.search(r"\(.+\)", s): ret_receive_view = fun_inside(s) # i是取出的括號及括號內的內容 for i in ret_receive_view: # ret是括號內的運算結果,而且將括號去掉 ret = cal_in_four(i.replace("(", "").replace(")", "")) # 此處應注意上面不管是加減仍是乘除的運算,函數的返回值所有是float類型 # 因此與str進行替換時須要進行轉換類型 s = s.replace(i, str(ret)) s = formatting(s) # 匹配不到括號進行最後的四則運算 else: result = cal_in_four(s) # 上面已經提到最終的運算結果爲float類型 return result li = "1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )" result_final = calculator(li) print(result_final)