二、軟件工程慕課第一章作業題——編寫一個計算器


課程地址:https://next.xuetangx.com/learn/THU08091000367/THU08091000367/1516221/exercise/138588

一、題目描述

  請用Python3編寫一個計算器的控制台程序,支持加減乘除、乘方、括號、小數點,運算符優先級為括號>乘方>乘除>加減,同級別運算按照從左向右的順序計算。

二、輸入描述

  1. 數字包括"0123456789",小數點為".",運算符包括:加("+")、減("-")、乘("*")、除("/")、乘方("^",注:不是**!)、括號("()")

  2. 需要從命令行參數讀入輸入,例如提交文件為main.py,可以用python3 main.py "1+2-3+4"的方式進行調用,Java程序也是類似的,如果你的程序需要通過鍵盤輸入,那么是不符合要求的,例如python使用input()來等待用戶輸入,這會因為自動評測時不會有用戶輸入所以不會有任何結果。

  3. 輸入需要支持空格,即 python3 main.py "1     +     2      -     3    +    4" 也需要程序能夠正確給出結果,Java程序也是類似的

  4. 所有測試用例中參與運算的非零運算數的絕對值范圍保證在 10^9-10^(-10) 之內, 應該輸出運算結果時非零運算結果絕對值也保證在該范圍內

三、輸出描述

  1. 數字需要支持小數點,輸出結果取10位有效數字,有效數字位數不足時不能補0

  2. 對於不在輸入描述內的輸入,輸出INPUT ERROR

  3. 對於格式不合法(例如括號不匹配等)的輸入,輸出 FORMAT ERROR

  4. 對於不符合運算符接收的參數范圍(例如除0等)的輸入,輸出VALUE ERROR

  5. 對於2、3、4的情況,輸出即可,不能拋出異常

  6. 同時滿足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中輸入時報錯:

 
查了下資料dos要這樣使用特殊字符需要加上轉義符^,即輸入 2^^2:

 

 
 

或者”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

程序運行如下

 

 
 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM