用python实现一个简单计算器(完整DEMO)


Posted in Python onOctober 14, 2020

一、功能目标

用户输入一个类似  1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))  这样的表达式,假设表达式里面除了包含空格、'+'、'-'、'*'、'/'和括号再无其他特殊符号,然后自己动手写代码解析其中的表达式,实现加减乘除最后得出的结果与真实的计算机所算的结果必须一致。

二、解题思路

1、为了分开运算符和数字,因此把输入的字符串格式转换为 列表的格式进行处理,这样子就可以按位进行 处理了

2、实现功能的核心点在于括号、乘除、加减的优先级排序,因此我们先想办法一层一层的去括号,即从最里层的括号开始计算,然后去掉第一层括号,然后一直继续这个 过程,最后得到一个没有括号的列表,再进行计算得出结果

3、去括号方式:最内层的括号内的表达式就可以当做一个无括号表达式,通过先 运算出乘除,再运算出加减得出整个括号内的值,用这个结果值整体替换括号内的内容即实现了去一层括号,然后通过递归去除所有的括号

4、去除乘除号方式:见 remove_multiplication_division(eq) 函数部分

5、去除加减号 方式:见 remove_plus_minus(eq) 函数部分

三、函数说明

1、主函数

def caculator(eq):
  format_list = eq_format(eq) # 把字符串变成格式化列表形式
  s_eq = simplify(format_list) # 去括号,得到无括号的一个格式化列表
  ans = calculate(s_eq)    # 计算最终结果
  if len(ans) == 2:      # 判断最终结果为正数还是负数
    ans = -float(ans[1])
  else:
    ans = float(ans[0])
  return ans

2、eq_format( )函数

def eq_format(eq):
  '''
  :param eq: 输入的算式字符串
  :return: 格式化以后的列表,如['60','+','7','*','8']
  '''
  format_list = re.findall('[\d\.]+|\(|\+|\-|\*|\/|\)',eq)
  return format_list

2.1 这个函数的作用是把输入的算式通过re模块,用正则表达式把算术符号和数字分开。

2.2  [\d\.]+ | \( | \+ | \- | \* | \/ | \)意思:按管道符号 | (| 表示 或 的意思)可分为几部分,[\d\.]+  是指匹配数字或小数点一次或多次,\(是指左括号,\+ 是指 加号,\- 是指减号,\* 是指乘号,\/ 是指除号, \) 是指右括号,整个正则表达式会把字符串变成类似['(','6','*','5','-''7',')' ]这样子的格式列表

3、simplify( ) 函数

def simplify(format_list):
  '''
  :param format_list: 输入的算式格式化列表如['60','+','7','*','8']
  :return: 通过递归去括号,返回简化后的列表
  '''
 
  bracket = 0   # 用于存放左括号在格式化列表中的索引
  count = 0
  for i in format_list:
    if i == '(':
      bracket = count
    elif i == ')':
      temp = format_list[bracket + 1 : count]
      # print(temp)
      new_temp = calculate(temp)
      format_list = format_list[:bracket] + new_temp + format_list[count+1:]
      format_list = change(format_list,bracket)   # 解决去括号后会出现的-- +- 问题
      return simplify(format_list)      # 递归去括号
    count = count + 1
  return format_list           # 当递归到最后一层的时候,不再有括号,因此返回列表

3.1 这个函数的作用是:把输入的带有括号的格式化列表,用递归的方式去除括号,每一次递归去一个括号, 直到没有括号则返回去完括号的格式化列表

3.2 找到最内层括号的方法:遍历列表,如果遇到左括号,则把当前左括号的索引赋值给参数bracket,直到遇到第一个右括号,此时的索引与bracket中间的元素即为最内层括号的元素,用切片的方式提取出来,通过 calculate() 函数计算出值,然后用计算结果去替换掉此时左括号到第一个右括号的元素,此时去除第一层括号,然后进入递归,不断递归直至去除所有括号

3.3 可能遇到的问题:

         首先是不要用index的方式去取当前左括号的索引,因为列表的index方法返回的一直都是第一个左括号的索引,而不是当前左括号的索引,会导致出错。因此我在函数内用参数 count 进行计数当前索引值。

          然后是用计算得出的值来替换掉第一层括号部分后,有可能会出现 ‘+-' ,‘ - -'的情况,要记得处理,我的函数中写了一个change() 函数进行处理

4、caculate()函数

def calculate(s_eq):
  '''
  :param s_eq: 不带括号的格式化列表
  :return: 计算结果
  '''
  if '*' or '/' in s_eq:
    s_eq = remove_multiplication_division(s_eq)
  if '+' or '-' in s_eq:
    s_eq = remove_plus_minus(s_eq)
  return s_eq

这个函数的作用是输入不带括号的格式化列表, 输出计算结果,然后返回结果列表

思路是先算乘除:remove_multiplication_division()函数,然后再从头到尾计算加减法:remove_plus_minus( )函数

5、remove_multiplication_division()函数

def remove_multiplication_division(eq):
  '''
  :param eq: 带有乘除号的格式化列表
  :return: 去除了乘除号的格式化列表
  '''
  count = 0
  for i in eq:
    if i == '*':
      if eq[count+1] != '-':
        eq[count-1] = float(eq[count-1]) * float(eq[count+1])
        del(eq[count])
        del(eq[count])
      elif eq[count+1] == '-':
        eq[count] = float(eq[count-1]) * float(eq[count+2])
        eq[count-1] = '-'
        del(eq[count+1])
        del(eq[count+1])
      eq = change(eq,count-1)
      return remove_multiplication_division(eq)
    elif i == '/':
      if eq[count+1] != '-':
        eq[count-1] = float(eq[count-1]) / float(eq[count+1])
        del(eq[count])
        del(eq[count])
      elif eq[count+1] == '-':
        eq[count] = float(eq[count-1]) / float(eq[count+2])
        eq[count-1] = '-'
        del(eq[count+1])
        del(eq[count+1])
      eq = change(eq,count-1)
      return remove_multiplication_division(eq)
    count = count + 1
  return eq

这个函数的作用是计算乘除,去乘除号。方法也是递归的方法,每次处理完一个乘号或者除号都可能出现符号问题,记得处理后再进入下一次递归

6、remove_plus_minus( )函数

def remove_plus_minus(eq):
  '''
  :param eq: 只带有加减号的格式化列表
  :return: 计算出整个列表的结果
  '''
  count = 0
  if eq[0] != '-':
    sum = float(eq[0])
  else:
    sum = 0.0
  for i in eq:
    if i == '-':
      sum = sum - float(eq[count+1])
    elif i == '+':
      sum = sum + float(eq[count+1])
    count = count + 1
  if sum >= 0:
    eq = [str(sum)]
  else:
    eq = ['-',str(-sum)]
  return eq

这个函数输入一个只有加减号的格式化列表,然后从头到尾的计算,得出最终结果,返回最终结果(结果形式也是列表)

7、change()函数

def change(eq,count):
  '''
  :param eq: 刚去完括号或者乘除后的格式化列表
  :param count: 发生变化的元素的索引
  :return: 返回一个不存在 '+-' ,'--'类的格式化列表
  '''
  if eq[count] == '-':
    if eq[count-1] == '-':
      eq[count-1] = '+'
      del eq[count]
    elif eq[count-1] == '+':
      eq[count-1] = '-'
      del eq[count]
  return eq

这个函数的作用是解决符号输入两个问题。输入参数1:刚去完括号的或者刚 计算完乘除的 格式化列表,输入参数2: 列表元素发生变化的索引(如去括号时,这个索引则为去括号前列表的最内层左括号的索引),输出结果是一个处理完符号问题或者什么都不做直接返回的列表

四、完整代码

需要的小伙伴,请关注微信公众号: Python客栈, 或者扫描下方公众号二维码,回复关键字:计算器, 即可免费无套路获取

用python实现一个简单计算器(完整DEMO)

↑关注上方公众号回复计算器 即可↑

程序运行结果

用python实现一个简单计算器(完整DEMO)

Python 相关文章推荐
Python ORM框架SQLAlchemy学习笔记之数据查询实例
Jun 10 Python
python基础教程之序列详解
Aug 29 Python
Python中使用HTMLParser解析html实例
Feb 08 Python
Python类属性与实例属性用法分析
May 09 Python
Python实现读取字符串按列分配后按行输出示例
Apr 17 Python
对Python 语音识别框架详解
Dec 24 Python
python下载微信公众号相关文章
Feb 26 Python
python3使用matplotlib绘制散点图
Mar 19 Python
Python小白必备的8个最常用的内置函数(推荐)
Apr 03 Python
Python可变和不可变、类的私有属性实例分析
May 31 Python
Python常用库大全及简要说明
Jan 17 Python
用Python提取PDF表格的方法
Apr 11 Python
python在linux环境下安装skimage的示例代码
Oct 14 #Python
python中如何使用虚拟环境
Oct 14 #Python
Python 3.9的到来到底是意味着什么
Oct 14 #Python
python破解同事的压缩包密码
Oct 14 #Python
如何Tkinter模块编写Python图形界面
Oct 14 #Python
python3实现语音转文字(语音识别)和文字转语音(语音合成)
Oct 14 #Python
如何利用Python 进行边缘检测
Oct 14 #Python
You might like
PHP session会话操作技巧小结
2016/09/27 PHP
ThinkPHP框架表单验证操作方法
2017/07/19 PHP
关于php支持的协议与封装协议总结(推荐)
2017/11/17 PHP
PHP实现的字符串匹配算法示例【sunday算法】
2017/12/19 PHP
一端时间轮换的广告
2006/06/26 Javascript
Node.js异步I/O学习笔记
2014/11/04 Javascript
JavaScript版的TwoQueues缓存模型
2014/12/29 Javascript
javascript为按钮注册回车事件(设置默认按钮)的方法
2015/05/09 Javascript
JS/jQuery判断DOM节点是否存在的简单方法
2016/11/24 Javascript
微信小程序 常见问题总结(4058,40013)及解决办法
2017/01/11 Javascript
vue.js利用Object.defineProperty实现双向绑定
2017/03/09 Javascript
chorme 浏览器记住密码后input黄色背景处理方法(两种)
2017/11/22 Javascript
纯js实现隔行变色效果
2017/11/29 Javascript
uni-app从安装到卸载的入门教程
2020/05/15 Javascript
Python实现新浪博客备份的方法
2016/04/27 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
python正则表达式及使用正则表达式的例子
2018/01/22 Python
Python简单实现的代理服务器端口映射功能示例
2018/04/08 Python
python实现电脑自动关机
2018/06/20 Python
python3读取excel文件只提取某些行某些列的值方法
2018/07/10 Python
Python实现App自动签到领取积分功能
2018/09/29 Python
python 实现将多条曲线画在一幅图上的方法
2019/07/07 Python
flask框架蓝图和子域名配置详解
2020/01/25 Python
video结合canvas实现视频在线截图功能
2018/06/25 HTML / CSS
印尼太阳百货公司网站:Matahari
2018/02/04 全球购物
类的返射机制中的包及核心类
2016/09/12 面试题
护士自我鉴定
2013/10/23 职场文书
2014党员学习《反腐倡廉警示教育读本》思想汇报
2014/09/13 职场文书
个人年终总结范文
2015/03/09 职场文书
优秀的商业计划书,让融资一步到位
2019/05/07 职场文书
2019脱贫攻坚工作总结报告范本!
2019/08/06 职场文书
MySQL 如何设计统计数据表
2021/06/15 MySQL
python之django路由和视图案例教程
2021/07/26 Python
Mysql中一千万条数据怎么快速查询
2021/12/06 MySQL
使用python创建股票的时间序列可视化分析
2022/03/03 Python
Nginx配置之禁止指定IP访问
2022/05/02 Servers