課程地址:https://next.xuetangx.com/learn/THU08091000367/THU08091000367/1516221/exercise/138588
一、題目描述
請用Python3編寫一個計算器的控制台程序,支持加減乘除、乘方、括號、小數點,運算符優先級為括號>乘方>乘除>加減,同級別運算按照從左向右的順序計算。
二、輸入描述
-
數字包括"0123456789",小數點為".",運算符包括:加("+")、減("-")、乘("*")、除("/")、乘方("^",注:不是**!)、括號("()")
-
需要從命令行參數讀入輸入,例如提交文件為main.py,可以用python3 main.py "1+2-3+4"的方式進行調用,Java程序也是類似的,如果你的程序需要通過鍵盤輸入,那么是不符合要求的,例如python使用input()來等待用戶輸入,這會因為自動評測時不會有用戶輸入所以不會有任何結果。
-
輸入需要支持空格,即 python3 main.py "1 + 2 - 3 + 4" 也需要程序能夠正確給出結果,Java程序也是類似的
-
所有測試用例中參與運算的非零運算數的絕對值范圍保證在 10^9-10^(-10) 之內, 應該輸出運算結果時非零運算結果絕對值也保證在該范圍內
三、輸出描述
-
數字需要支持小數點,輸出結果取10位有效數字,有效數字位數不足時不能補0
-
對於不在輸入描述內的輸入,輸出INPUT ERROR
-
對於格式不合法(例如括號不匹配等)的輸入,輸出 FORMAT ERROR
-
對於不符合運算符接收的參數范圍(例如除0等)的輸入,輸出VALUE ERROR
-
對於2、3、4的情況,輸出即可,不能拋出異常
-
同時滿足2、3、4中多個條件時,以序號小的為准
四、樣例
輸入: 1 + 2 - 3 + 4
輸出: 4
輸入: 1 + 2 - 3 + 1 / 3
輸出: 0.3333333333
輸入: 1 + + 2
輸出: FORMAT ERROR
輸入: 1 / 0
輸出: VALUE ERROR
輸入: a + 1
輸出: INPUT ERROR
五、思路總結
python中有一個eval函數可以直接進行算式的計算,但我估計這個作業的目的是讓我們自己實現,故先對式子進行處理,式子的處理查閱了網上的一些方法,覺得自己能理解和寫出來的就是利用正則表達式將字符串形式的算式變成列表,然后進行處理
1 import re 2 3 def conversionFormula(formula): 4 5 format_list = re.findall('[\w\.]+|\(|\+|\-|\*|\/|\^|\)',formula) 6 7 return format_list
這里要用到re庫的方法對接收的字符串進行列表的轉換,例如接受[1+2*3],轉換后為[ '1', '+', '2', '*', '3' ],轉換完成后就是對式子進行分析,最重要的就是對括號的處理,我采取的方法是對列表進行遍歷,找到最內層的括號,然后對里面的式子進行求解,然后將此括號及中間的算式替換成答案,然后遞歸進行新式子的求解。下面貼出的方法可以將將列表里的括號及括號里的式子處理完畢后進行返回,格式依然是列表
1 def remove_bracket(formula): 2 leftBracket = 0 3 count = 0 #用遍歷列表進行計數 4 5 for i in formula: 6 if i == '(': #記錄最內側左括號的位置 7 8 leftBracket=count 9 10 elif i == ')': 11 12 smallestFomula = formula[leftBracket+1:count] #提取最內層括號里式子 13 smallestFomulaAnswer = calculator(smallestFomula) #調用calculator方法進行計算 14 15 if smallestFomulaAnswer < 0: #更新式子,對去括號后的+-,--情況進行分析 16 if formula[leftBracket-1] == '-': 17 formula[leftBracket-1] = '+' 18 temp = formula[:leftBracket] 19 temp.append(str(abs(smallestFomulaAnswer))) 20 formula = temp+formula[count+1:] 21 22 elif formula[leftBracket-1] == '+': 23 formula[leftBracket-1] = '-' 24 temp = formula[:leftBracket] 25 temp.append(str(abs(smallestFomulaAnswer))) 26 formula = temp+formula[count+1:] 27 28 else: 29 temp = formula[:leftBracket] 30 temp.append(str(smallestFomulaAnswer)) 31 formula = temp+formula[count+1:] 32 33 else: 34 temp = formula[:leftBracket] 35 temp.append(str(smallestFomulaAnswer)) 36 formula = temp+formula[count+1:] 37 38 return remove_bracket(formula) #遞歸,進行新式子的去括號分析 39 40 count+=1 41 42 return formula #返回無括號的最終式子
還有一部分就是對括號內的式子進行計算
1 def calculator(formula): 2 count = 0 3 for i in formula: #先處理乘方、乘除 4 if i == '^': 5 formula[count-1]=str(float(formula[count-1])**float(formula[count+1])) 6 del(formula[count]) 7 del(formula[count]) 8 return calculator(formula) 9 10 elif i == '*': 11 formula[count-1]=str(float(formula[count-1])*float(formula[count+1])) 12 del(formula[count]) 13 del(formula[count]) 14 return calculator(formula) 15 16 elif i == '/': 17 formula[count-1]=str(float(formula[count-1])/float(formula[count+1])) 18 del(formula[count]) 19 del(formula[count]) 20 return calculator(formula) 21 22 count+=1 23 24 count=0 25 26 if formula[0]=='-': #處理第一個字符是’-’的情況 27 formula[1]=formula[0]+formula[1] 28 del(formula[0]) 29 30 for i in formula: #處理加減 31 if i == '+': 32 formula[count-1]=str(float(formula[count-1])+float(formula[count+1])) 33 del(formula[count]) 34 del(formula[count]) 35 return calculator(formula) 36 37 elif i == '-': 38 formula[count-1]=str(float(formula[count-1])-float(formula[count+1])) 39 del(formula[count]) 40 del(formula[count]) 41 return calculator(formula) 42 43 count+=1 44 45 return float(formula[0]) 返回float型的運算結果
最后是在主函數里對上述兩個方法進行調用
1 if __name__ == '__main__': 2 3 formula=input('請輸入算式:') 4 formula="".join(formula.split()) 5 formula = eq_format(formula) 6 formula = remove_bracket(formula) 7 answer = calculator(formula) 8 print(answer)
六、完善
到上述部分,大體功能就完成了,下面進行一些修修補補,要求里需要對空格、格式不對、補0等問題進行處理主要修改的有conversionFormula和主函數一些地方,下面貼出代碼
1 def conversionFormula(formula): 2 3 format_list = re.findall('[\w\.]+|\(|\+|\-|\*|\/|\^|\)',formula) 4 switch =0 5 switch2=0 6 count=0 7 for i in format_list: 8 if i == '(' or i == ')': #進行括號符號的判斷 9 switch2+=1 10 11 for i in format_list: 12 if i == '+' or i == '-' or i == '*' or i == '/' or i == '^':#進行加減乘除乘方符號的判斷
13 switch =1 14 break 15 if switch != 1 : 16 print('INPUT ERROR') 17 return 'ERROR' 18 for i in format_list: #進行一些錯誤的判斷 19 if i == '+' or i == '-' or i == '*' or i == '/' : 20 if format_list[count-1] == '+' or format_list[count-1] == '-' or\ 21 format_list[count-1] == '*' or format_list[count-1] == '/' or\ 22 format_list[count+1] == '+' or format_list[count+1] == '-' or\ 23 format_list[count+1] == '*' or format_list[count+1] == '/' : 24 print('FORMAT ERROR') 25 return 'ERROR' 26 elif i == '/' and format_list[count+1] == '0': 27 28 print('VALUE ERROR') 29 return 'ERROR' 30 elif i.isalpha() == True: 31 print('INPUT ERROR') 32 return 'ERROR' 33 count+=1 34 if switch2 % 2 != 0: 35 print('FORMAT ERROR') 36 return 'ERROR' 37 38 return format_list
1 if __name__ == '__main__': 2 3 formula=input('輸入:') 4 formula="".join(shizi.split()) #空格處理 5 formula = conversionFormula(formula) 6 7 if formula != 'ERROR': #錯誤判斷 8 formula = remove_bracket(formula) 9 answer = calculator(formula) 10 if float(answer).is_integer() == True: 11 answer=int(answer) 12 else: 13 answer=format(answer,'.10f') #空格補0,不足位數不補0 14 answer=float(str(answer).rstrip('0')) 15 print(answer) 16 else: 17 a=1
到此還有一個從命令行輸入參數的要求,故將主函數中輸入參數部分作修改
1 if __name__ == '__main__': 2 3 formula="".join(sys.argv[1:]) 4 formula = conversionFormula(formula) 5 6 if formula != 'ERROR': #錯誤判斷 7 formula = remove_bracket(formula) 8 answer = calculator(formula) 9 if float(answer).is_integer() == True: 10 answer=int(answer) 11 else: 12 answer=format(answer,'.10f') #空格補0,不足位數不補0 13 answer=float(str(answer).rstrip('0')) 14 print(answer) 15 else: 16 a=1
這里在調試的時候遇到一個問題,題目要求乘方按照2^2的形式輸入,我在dos中輸入時報錯:


或者”2^2"

1 import re 2 import sys 3 4 5 def conversionFormula(formula): 6 7 format_list = re.findall('[\w\.]+|\(|\+|\-|\*|\/|\^|\)',formula) 8 switch =0 9 switch2=0 10 count=0 11 for i in format_list: 12 if i == '(' or i == ')': 13 switch2+=1 14 15 for i in format_list: 16 if i == '+' or i == '-' or i == '*' or i == '/' or i == '^': 17 switch =1 18 break 19 if switch != 1 : 20 print('INPUT ERROR') 21 return 'ERROR' 22 for i in format_list: 23 if i == '+' or i == '-' or i == '*' or i == '/' : 24 if format_list[count-1] == '+' or format_list[count-1] == '-' or\ 25 format_list[count-1] == '*' or format_list[count-1] == '/' or\ 26 format_list[count+1] == '+' or format_list[count+1] == '-' or\ 27 format_list[count+1] == '*' or format_list[count+1] == '/' : 28 print('FORMAT ERROR') 29 return 'ERROR' 30 elif i == '/' and format_list[count+1] == '0': 31 32 print('VALUE ERROR') 33 return 'ERROR' 34 elif i.isalpha() == True: 35 print('INPUT ERROR') 36 return 'ERROR' 37 count+=1 38 if switch2 % 2 != 0: 39 print('FORMAT ERROR') 40 return 'ERROR' 41 42 return format_list 43 44 45 def calculator(formula): 46 count = 0 47 for i in formula: 48 49 if i == '^': 50 formula[count-1]=str(float(formula[count-1])**float(formula[count+1])) 51 del(formula[count]) 52 del(formula[count]) 53 return calculator(formula) 54 55 if i == '*': 56 formula[count-1]=str(float(formula[count-1])*float(formula[count+1])) 57 del(formula[count]) 58 del(formula[count]) 59 return calculator(formula) 60 61 elif i == '/': 62 formula[count-1]=str(float(formula[count-1])/float(formula[count+1])) 63 del(formula[count]) 64 del(formula[count]) 65 return calculator(formula) 66 67 count+=1 68 69 count=0 70 71 if formula[0]=='-': 72 formula[1]=formula[0]+formula[1] 73 del(formula[0]) 74 75 for i in formula: 76 77 if i == '+': 78 formula[count-1]=str(float(formula[count-1])+float(formula[count+1])) 79 del(formula[count]) 80 del(formula[count]) 81 return calculator(formula) 82 83 elif i == '-': 84 formula[count-1]=str(float(formula[count-1])-float(formula[count+1])) 85 del(formula[count]) 86 del(formula[count]) 87 return calculator(formula) 88 89 count+=1 90 91 return float(formula[0]) 92 93 def remove_bracket(formula): 94 leftBracket = 0 95 count = 0 #用遍歷列表進行計數 96 97 for i in formula: 98 if i == '(': 99 100 leftBracket=count 101 elif i == ')': 102 103 smallestFomula = formula[leftBracket+1:count] 104 smallestFomulaAnswer = calculator(smallestFomula) 105 if smallestFomulaAnswer < 0: 106 if formula[leftBracket-1] == '-': 107 formula[leftBracket-1] = '+' 108 temp = formula[:leftBracket] 109 temp.append(str(abs(smallestFomulaAnswer))) 110 formula = temp+formula[count+1:] 111 112 elif formula[leftBracket-1] == '+': 113 formula[leftBracket-1] = '-' 114 temp = formula[:leftBracket] 115 temp.append(str(abs(smallestFomulaAnswer))) 116 formula = temp+formula[count+1:] 117 118 else: 119 temp = formula[:leftBracket] 120 temp.append(str(smallestFomulaAnswer)) 121 formula = temp+formula[count+1:] 122 else: 123 temp = formula[:leftBracket] 124 temp.append(str(smallestFomulaAnswer)) 125 formula = temp+formula[count+1:] 126 127 return remove_bracket(formula) 128 count+=1 129 130 return formula 131 132 if __name__ == '__main__': 133 134 formula="".join(sys.argv[1:]) 135 formula = conversionFormula(formula) 136 137 if formula != 'ERROR': 138 formula = remove_bracket(formula) 139 answer = calculator(formula) 140 if float(answer).is_integer() == True: 141 answer=int(answer) 142 else: 143 answer=format(answer,'.10f') 144 answer=float(str(answer).rstrip('0')) 145 print(answer) 146 else: 147 a=1
程序運行如下