zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    [置顶] 签名时出错: 未在路径 C:Program Files (x86)Microsoft SDKsWindowsv7.0Ainsigntool.exe 找到 SignTool.ex
    频繁绑定DataGridView的DataSource却不正常显示
    生产者消费者模型 android
    Android Studio安装插件的三种方式
    Android Studio插件安装
    数据调试~~TCP转串口、串口转TCP调试
    Socket看法
    android颜色color.xml设置
    博客导航——一站式搜索
    dx.jar文件问题,有没有同学知道怎么解决呀,这一步没法解决,后面就没办法跟着做了
  • 原文地址:https://www.cnblogs.com/visonwong/p/9171517.html
Copyright © 2011-2022 走看看