Python实践之路7——计算器

一、代码需求

  开发一个简单的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 #!/user/bin/env ptyhon
  2 # -*- coding:utf-8 -*-
  3 # Author: VisonWong
  4 
  5 import re
  6 
  7 
  8 def compute_mul_div(arg):
  9     """ 操作乘除
 10     :param expression:表达式
 11     :return:计算结果
 12     """
 13 
 14     val = arg[0]
 15     #第一组形如 -40.0/5 可以匹配到 40.0/5
 16     #匹配方法解释:\d+\.*\d* 可以匹配到任意实数和小数  [\*\/]可以匹配到乘除号  [\+\-]?\d+\.*\d*可以匹配到任意带符号的任意实数和小数
 17     mch = re.search('\d+\.*\d*[\*\/][\+\-]?\d+\.*\d*', val)
 18     if not mch:
 19         return
 20     content = re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', val).group()
 21 
 22     if len(content.split('*')) > 1:
 23         n1, n2 = content.split('*')
 24         value = float(n1) * float(n2)
 25     else:
 26         n1, n2 = content.split('/')
 27         value = float(n1) / float(n2)
 28 
 29     before, after = re.split('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', val, 1)
 30     new_str = "%s%s%s" % (before, value, after)
 31     arg[0] = new_str
 32     compute_mul_div(arg)
 33 
 34 
 35 def compute_add_sub(arg):
 36     """ 操作加减
 37     :param expression:表达式
 38     :return:计算结果
 39     """
 40     while True:
 41         if arg[0].__contains__('+-') or arg[0].__contains__("++") or arg[0].__contains__('-+') or arg[0].__contains__(
 42                 "--"):
 43             arg[0] = arg[0].replace('+-', '-')
 44             arg[0] = arg[0].replace('++', '+')
 45             arg[0] = arg[0].replace('-+', '-')
 46             arg[0] = arg[0].replace('--', '+')
 47         else:
 48             break
 49 
 50     #替换符号:如出现-5+6.2-7替换为5-6.2+7,并在替换计数位加1
 51     if arg[0].startswith('-'):
 52         arg[1] += 1
 53         arg[0] = arg[0].replace('-', '&')
 54         arg[0] = arg[0].replace('+', '-')
 55         arg[0] = arg[0].replace('&', '+')
 56         arg[0] = arg[0][1:]
 57     val = arg[0]
 58     #第一组形如 40.0+5-8 可以匹配到 40.0+5
 59     #匹配方法解释:\d+\.*\d* 可以匹配到任意实数和小数  [\+\-]可以匹配到乘除号
 60     mch = re.search('\d+\.*\d*[\+\-]{1}\d+\.*\d*', val)
 61     if not mch:
 62         return
 63     content = re.search('\d+\.*\d*[\+\-]{1}\d+\.*\d*', val).group()
 64     if len(content.split('+')) > 1:
 65         n1, n2 = content.split('+')
 66         value = float(n1) + float(n2)
 67     else:
 68         n1, n2 = content.split('-')
 69         value = float(n1) - float(n2)
 70 
 71     before, after = re.split('\d+\.*\d*[\+\-]{1}\d+\.*\d*', val, 1)
 72     new_str = "%s%s%s" % (before, value, after)
 73     arg[0] = new_str
 74     compute_add_sub(arg)
 75 
 76 
 77 def compute(expression):
 78     """ 操作加减乘除
 79     :param expression:表达式
 80     :return:计算结果
 81     """
 82     inp = [expression, 0]
 83 
 84     # 处理表达式中的乘除
 85     compute_mul_div(inp)
 86 
 87     # 处理表达式中的加减
 88     compute_add_sub(inp)
 89 
 90     if divmod(inp[1], 2)[1] == 1:
 91         result = float(inp[0])
 92         result = result * -1
 93     else:
 94         result = float(inp[0])
 95     return result
 96 
 97 
 98 def exec_bracket(expression):
 99     """ 递归处理括号,并计算
100     :param expression: 表达式
101     :return:最终计算结果
102     """
103     # 如果表达式中已经没有括号,则直接调用负责计算的函数,将表达式结果返回,如:2*1-82+444
104     if not re.search('\([^()]+\)', expression):
105         final = compute(expression)
106         return final
107     # 获取 第一个只含有数字/小数和操作符的括号
108     # 如:
109     #    ['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
110     #    找出:(-40.0/5)
111     content = re.search('\([^()]+\)', expression).group()
112 
113     # 分割表达式,即:
114     # 将['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
115     # 分割更三部分:['1-2*((60-30+(    (-40.0/5)      *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
116     # 最后参数1代表仅分割第一个符合条件的部分
117     before,after = re.split('\([^()]+\)', expression, 1)
118 
119     print('before:', expression)
120     content = re.sub("[()]", "", content)  # 去除两边的()
121 
122     # 计算,提取的表示 -40.0/5,并计算结果,即:-40.0/5=-8.0
123     ret = compute(content)
124 
125     print('%s=%s' % (content, ret))
126 
127     # 将执行结果拼接,['1-2*((60-30+(      -8.0     *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
128     expression = "%s%s%s" % (before, ret, after)
129     print('after:', expression)
130     print("=" * 10, '上一次计算结束', "=" * 10)
131 
132     # 循环继续下次括号处理操作,本次携带者的是已被处理后的表达式,即:
133     # ['1-2*((60-30+   -8.0  *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
134 
135     # 递归调用本身,如此周而复始的操作,直到表达式中不再含有括号
136     return exec_bracket(expression)
137 
138 
139 # 使用 __name__ 的目的:
140 #   只有执行 python index.py 时,以下代码才执行
141 #   如果其他人导入该模块,以下代码不执行
142 if __name__ == "__main__":
143     print ('*'*20,"请计算表达式:", "1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )" ,'*'*20)
144     inpp = '1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) '
145     # inpp = "1-2*-30/-12*(-20+200*-3/-200*-300-100)"
146     # inpp = "1-5*980.0"
147 
148     inpp = re.sub('\s*', '', inpp)    #去掉空白字符
149 
150     # 表达式保存在列表中
151     result = exec_bracket(inpp)
152     print(result)
153     
154     
155     
156 
157 # ******************** 请计算表达式: 1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) ********************
158 # before: 1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
159 # -40.0/5=-8.0
160 # after: 1-2*((60-30+-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
161 # ========== 上一次计算结束 ==========
162 # before: 1-2*((60-30+-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
163 # 9-2*5/3+7/3*99/4*2998+10*568/14=173545.88095238098
164 # after: 1-2*((60-30+-8.0*173545.88095238098)-(-4*3)/(16-3*2))
165 # ========== 上一次计算结束 ==========
166 # before: 1-2*((60-30+-8.0*173545.88095238098)-(-4*3)/(16-3*2))
167 # 60-30+-8.0*173545.88095238098=-1388337.0476190478
168 # after: 1-2*(-1388337.0476190478-(-4*3)/(16-3*2))
169 # ========== 上一次计算结束 ==========
170 # before: 1-2*(-1388337.0476190478-(-4*3)/(16-3*2))
171 # -4*3=-12.0
172 # after: 1-2*(-1388337.0476190478--12.0/(16-3*2))
173 # ========== 上一次计算结束 ==========
174 # before: 1-2*(-1388337.0476190478--12.0/(16-3*2))
175 # 16-3*2=10.0
176 # after: 1-2*(-1388337.0476190478--12.0/10.0)
177 # ========== 上一次计算结束 ==========
178 # before: 1-2*(-1388337.0476190478--12.0/10.0)
179 # -1388337.0476190478--12.0/10.0=-1388335.8476190479
180 # after: 1-2*-1388335.8476190479
181 # ========== 上一次计算结束 ==========
182 # 2776672.6952380957

 

posted @ 2018-06-12 09:27  VisonWong  阅读(221)  评论(0编辑  收藏  举报