二、软件工程慕课第一章作业题——编写一个计算器

课程地址: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

程序运行如下

 

 
 

 

 

 

 

 

posted @ 2020-02-22 18:54  认真学习的小朋友  阅读(1140)  评论(1编辑  收藏  举报