作業需求:
開發一個簡單的python計算器
1、實現加減乘除及拓號優先級解析
2、用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式后,必須自己解析里面的(),+,-,*,/符號和公式(不能調用eval等類似功能偷懶實現),運算后得出結果,結果必須與真實的計算器所得出的結果一致

上圖是實現的邏輯思路圖,下面是對上圖的分析:
整體的思想就是先匹配最小的括號例如:1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) 從這個公式來看,應該先匹配到(-40/5),將這個括號里的公式進行計算,計算后將內容把(-40/5)替換掉,依次類推,將所有的括號都進行這樣的計算與替換,在計算括號里的公式的時候需要注意的問題應該先匹配乘除進行計算與替換直到公式中沒有乘除,然后再匹配加減進行計算與替換,直到匹配不到加減,這樣最后的結果就是首先將括號里的內容計算並匹配,得到了一個只存在加減乘除的公式,這個時候和計算括號里的公式的方法一樣,先匹配乘除計算並替換,然后匹配加減計算並替換,這樣最后就能計算得出答案。
下列代碼是整個的實現過程:注意:下面的代碼並沒有對輸入公式的正確進行判斷,但是已經實現了如果輸入正確的公式都能正常計算
1 import re 2 #匹配整數或小數的乘除法,包括了開頭存在減號的情況 3 mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\.\d+)?") 4 #匹配整數或小數的加減法,包括了開頭存在減號的情況 5 plus_minus = re.compile("(-?\d+)(\.\d+)?(-|\+)(-?\d+)(\.\d+)?") 6 #匹配括號 7 bracket=re.compile("\([^()]*\)") 8 #匹配乘法的時候出現乘以負數的情況,包括了開頭存在減號的情況 9 mul_minus_minus = re.compile("(-?\d+)(\.\d+)?(\*-)(\d+)(\.\d+)?") 10 #匹配除法的時候出現乘以負數的情況,包括了開頭存在減號的情況 11 div_minus_minus = re.compile("(-?\d+)(\.\d+)?(/-)(\d+)(\.\d+)?") 12 13 14 #定義一個兩位數的加減乘除法的運算,匹配左邊的右邊的數字和左邊的數字,然后進行計算 15 def touble_cale(str_expire): 16 if str_expire.count("+") == 1: 17 right_num = float(str_expire[(str_expire.find("+")+1):]) 18 left_num = float(str_expire[:str_expire.find("+")]) 19 return str(right_num+left_num) 20 elif str_expire[1:].count("-") == 1: 21 right_num = float(str_expire[:str_expire.find("-",1)]) 22 left_num = float(str_expire[(str_expire.find("-", 1) + 1):]) 23 return str(right_num - left_num) 24 elif str_expire.count("*") == 1: 25 right_num = float(str_expire[:str_expire.find("*")]) 26 left_num = float(str_expire[(str_expire.find("*")+1):]) 27 return str(right_num * left_num) 28 elif str_expire.count("/") == 1: 29 right_num = float(str_expire[:str_expire.find("/")]) 30 left_num = float(str_expire[(str_expire.find("/") + 1):]) 31 return str(right_num / left_num) 32 33 34 #定義一個方法用於判斷是否存在乘以負數和除以負數的情況 35 def judge_mul_minus(str_expire): 36 #判斷公式中乘以負數的部分 37 if len(re.findall("(\*-)", str_expire)) != 0: 38 #調用上面的正則取得*-的公式 39 temp_mul_minus = mul_minus_minus.search(str_expire).group() 40 #將匹配的部分的*-換成*並將-放到前面 41 temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*")) 42 #經更改的的部分與原來的部分進行替換 43 str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2) 44 return judge_mul_minus(str_expire) 45 #return str_expire 46 # 判斷公式中除以負數的部分 47 elif len(re.findall(r"(/-)", str_expire)) != 0: 48 # 調用上面的正則取得/-的公式 49 temp_dev_minus = div_minus_minus.search(str_expire).group() 50 # 將匹配的部分的/-換成/並將-放到前面 51 temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/")) 52 # 經更改的的部分與原來的部分進行替換 53 str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2) 54 return judge_mul_minus(str_expire) 55 #調用change_sign將公式中的++換成= +-換成- 56 return change_sign(str_expire) 57 58 #定義一個方法取將--更改為+ +-改為- 59 def change_sign(str_expire): 60 if len(re.findall(r"(\+-)", str_expire)) != 0: 61 str_expire = str_expire.replace("+-", "-") 62 return change_sign(str_expire) 63 elif len(re.findall(r"(--)", str_expire)) != 0: 64 str_expire = str_expire.replace("--", "+") 65 return change_sign(str_expire) 66 return str_expire 67 68 69 #定義一個方法用於計算只有加減乘除的公式,優先處理乘法 70 def cale_mix(str_expire): 71 #如果公式中出現符號數字的情況即+5 -6 *8 /8的這種情況直接放回數字否則則先計算乘除在處理加減 72 while len(re.findall("[-+*/]",str_expire[1:])) != 0: 73 if len(re.findall("(\*|/)",str_expire)) != 0: 74 str_expire = str_expire.replace(mul_div.search(str_expire).group(),touble_cale(mul_div.search(str_expire).group())) 75 elif len(re.findall("(\+|-)",str_expire)) !=0: 76 str_expire = str_expire.replace(plus_minus.search(str_expire).group(),touble_cale(plus_minus.search(str_expire).group())) 77 return str_expire 78 79 #定義一個方法用於去括號,並調用上述的方法進行計算 80 def remove_bracket(str_expire): 81 #判斷公式中是否有括號 82 if len(bracket.findall(str_expire)) == 0: 83 return cale_mix(judge_mul_minus(str_expire)) 84 elif len(bracket.findall(str_expire))!=0: 85 while len(bracket.findall(str_expire)) !=0: 86 #print(bracket.search(str_expire).group()) 87 #只有存在括號優先處理括號中的內容並對內容進行替換,直到沒有括號位置 88 str_expire = str_expire.replace(bracket.search(str_expire).group(),cale_mix(judge_mul_minus(bracket.search(str_expire).group()[1:-1]))) 89 str_expire = cale_mix(judge_mul_minus(str_expire)) 90 return str_expire 91 92 93 if __name__ == "__main__": 94 while True: 95 user_input_expire = input("請輸入你的公式:(不要帶空格,q表示退出):") 96 print("%s=%s" %(user_input_expire,remove_bracket(user_input_expire))) 97 continue
下面將代碼進行分析:
首先是用寫正則,一次匹配乘除法的正則,但是寫的時候需要注意正則前面喲一個"-?",表示匹配乘除的時候需要匹配前面的減號。同樣類似的方法匹配加減法,
然后是匹配括號,這個也是整個過程中非常重要的一個地方:bracket=re.compile("\([^()]*\)")
接着是匹配乘以負數的情況已經除以負數的情況
1 #匹配整數或小數的乘除法,包括了開頭存在減號的情況 2 mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\.\d+)?") 3 #匹配整數或小數的加減法,包括了開頭存在減號的情況 4 plus_minus = re.compile("(-?\d+)(\.\d+)?(-|\+)(-?\d+)(\.\d+)?") 5 #匹配括號 6 bracket=re.compile("\([^()]*\)") 7 #匹配乘法的時候出現乘以負數的情況,包括了開頭存在減號的情況 8 mul_minus_minus = re.compile("(-?\d+)(\.\d+)?(\*-)(\d+)(\.\d+)?") 9 #匹配除法的時候出現乘以負數的情況,包括了開頭存在減號的情況 10 div_minus_minus = re.compile("(-?\d+)(\.\d+)?(/-)(\d+)(\.\d+)?")
接着下面的這個方法是用於匹配兩位數的四則運算
1 #定義一個兩位數的加減乘除法的運算,匹配左邊的右邊的數字和左邊的數字,然后進行計算 2 def touble_cale(str_expire): 3 if str_expire.count("+") == 1: 4 right_num = float(str_expire[(str_expire.find("+")+1):]) 5 left_num = float(str_expire[:str_expire.find("+")]) 6 return str(right_num+left_num) 7 elif str_expire[1:].count("-") == 1: 8 right_num = float(str_expire[:str_expire.find("-",1)]) 9 left_num = float(str_expire[(str_expire.find("-", 1) + 1):]) 10 return str(right_num - left_num) 11 elif str_expire.count("*") == 1: 12 right_num = float(str_expire[:str_expire.find("*")]) 13 left_num = float(str_expire[(str_expire.find("*")+1):]) 14 return str(right_num * left_num) 15 elif str_expire.count("/") == 1: 16 right_num = float(str_expire[:str_expire.find("/")]) 17 left_num = float(str_expire[(str_expire.find("/") + 1):]) 18 return str(right_num / left_num)
這個方法是用於判斷存在乘以負數的時候和除以負數的情況如何處理,這里的操作是將負號放到公式的前面,然后將公式中的*-和/-都換成*和/
1 #定義一個方法用於判斷是否存在乘以負數和除以負數的情況 2 def judge_mul_minus(str_expire): 3 #判斷公式中乘以負數的部分 4 if len(re.findall("(\*-)", str_expire)) != 0: 5 #調用上面的正則取得*-的公式 6 temp_mul_minus = mul_minus_minus.search(str_expire).group() 7 #將匹配的部分的*-換成*並將-放到前面 8 temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*")) 9 #經更改的的部分與原來的部分進行替換 10 str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2) 11 return judge_mul_minus(str_expire) 12 #return str_expire 13 # 判斷公式中除以負數的部分 14 elif len(re.findall(r"(/-)", str_expire)) != 0: 15 # 調用上面的正則取得/-的公式 16 temp_dev_minus = div_minus_minus.search(str_expire).group() 17 # 將匹配的部分的/-換成/並將-放到前面 18 temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/")) 19 # 經更改的的部分與原來的部分進行替換 20 str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2) 21 return judge_mul_minus(str_expire) 22 #調用change_sign將公式中的++換成= +-換成- 23 return change_sign(str_expire)
下面的方法用於將公式中可能會出現++和--的情況,將其替換為++替換為+將--替換為+
1 #定義一個方法取將--更改為+ +-改為- 2 def change_sign(str_expire): 3 if len(re.findall(r"(\+-)", str_expire)) != 0: 4 str_expire = str_expire.replace("+-", "-") 5 return change_sign(str_expire) 6 elif len(re.findall(r"(--)", str_expire)) != 0: 7 str_expire = str_expire.replace("--", "+") 8 return change_sign(str_expire) 9 return str_expire
這個方法用於處理括號里面的四則運算以及整個公式沒有括號,只剩下四則運算的情況,優先匹配乘除計算,如果沒有乘除了匹配加減進行計算
1 #定義一個方法用於計算只有加減乘除的公式,優先處理乘法 2 def cale_mix(str_expire): 3 #如果公式中出現符號數字的情況即+5 -6 *8 /8的這種情況直接放回數字否則則先計算乘除在處理加減 4 while len(re.findall("[-+*/]",str_expire[1:])) != 0: 5 if len(re.findall("(\*|/)",str_expire)) != 0: 6 str_expire = str_expire.replace(mul_div.search(str_expire).group(),touble_cale(mul_div.search(str_expire).group())) 7 elif len(re.findall("(\+|-)",str_expire)) !=0: 8 str_expire = str_expire.replace(plus_minus.search(str_expire).group(),touble_cale(plus_minus.search(str_expire).group())) 9 return str_expire
下面的方法用於匹配括號用,匹配到括號后調用上面的方法進行計算和替換,直到整個公式計算完畢
1 #定義一個方法用於去括號,並調用上述的方法進行計算 2 def remove_bracket(str_expire): 3 #判斷公式中是否有括號 4 if len(bracket.findall(str_expire)) == 0: 5 return cale_mix(judge_mul_minus(str_expire)) 6 elif len(bracket.findall(str_expire))!=0: 7 while len(bracket.findall(str_expire)) !=0: 8 #print(bracket.search(str_expire).group()) 9 #只有存在括號優先處理括號中的內容並對內容進行替換,直到沒有括號位置 10 str_expire = str_expire.replace(bracket.search(str_expire).group(),cale_mix(judge_mul_minus(bracket.search(str_expire).group()[1:-1]))) 11 str_expire = cale_mix(judge_mul_minus(str_expire)) 12 return str_expire
1 if __name__ == "__main__": 2 while True: 3 user_input_expire = input("請輸入你的公式:(不要帶空格,q表示退出):") 4 print("%s=%s" %(user_input_expire,remove_bracket(user_input_expire))) 5 continue
