用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中使用enumerate函数遍历元素实例
Jun 16 Python
python实现的文件同步服务器实例
Jun 02 Python
Django框架的中的setting.py文件说明详解
Oct 15 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 Python
详解Appium+Python之生成html测试报告
Jan 04 Python
Python之列表实现栈的工作功能
Jan 28 Python
Python流行ORM框架sqlalchemy安装与使用教程
Jun 04 Python
Python中关于logging模块的学习笔记
Jun 03 Python
python爬虫把url链接编码成gbk2312格式过程解析
Jun 08 Python
python与pycharm有何区别
Jul 01 Python
python中如何打包用户自定义模块
Sep 23 Python
用python制作个视频下载器
Feb 01 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 smtp实现发送邮件功能
2017/06/22 PHP
彻底搞懂PHP 变量结构体
2017/10/11 PHP
学习jquery之一
2007/04/27 Javascript
用cookies实现的可记忆的样式切换效果代码下载
2007/12/24 Javascript
用JS控制回车事件的代码
2011/02/20 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
dwz 如何去掉ajaxloading具体代码
2013/05/22 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
JavaScript中window.open用法实例详解
2015/04/15 Javascript
jQuery预加载图片常用方法
2015/06/15 Javascript
有关文件上传 非ajax提交 得到后台数据问题
2016/10/12 Javascript
用vue的双向绑定简单实现一个todo-list的示例代码
2017/08/03 Javascript
10个经典的网页鼠标特效代码
2018/01/09 Javascript
vue项目中jsonp跨域获取qq音乐首页推荐问题
2018/05/30 Javascript
js实现适配移动端的拖动效果
2020/01/13 Javascript
解决vue-cli输入命令vue ui没效果的问题
2020/11/17 Javascript
[03:26]回顾2015国际邀请赛中国区预选赛
2015/06/09 DOTA
[01:20]DOTA2更新全新英雄 天涯墨客现已加入游戏
2018/08/25 DOTA
python&MongoDB爬取图书馆借阅记录
2016/02/05 Python
Python实现将doc转化pdf格式文档的方法
2018/01/19 Python
Python列表与元组的异同详解
2019/07/02 Python
Python Request爬取seo.chinaz.com百度权重网站的查询结果过程解析
2019/08/13 Python
Python Pillow.Image 图像保存和参数选择方式
2020/01/09 Python
PyQt5中多线程模块QThread使用方法的实现
2020/01/31 Python
利用python中集合的唯一性实现去重
2020/02/11 Python
python 链接sqlserver 写接口实例
2020/03/11 Python
Python sorted对list和dict排序
2020/06/09 Python
python实现mean-shift聚类算法
2020/06/10 Python
使用HTML5和CSS3表单验证功能
2017/05/05 HTML / CSS
大学自荐信
2013/12/12 职场文书
黄河象教学反思
2014/02/10 职场文书
我爱我家教学反思
2014/05/01 职场文书
电视节目策划方案
2014/05/16 职场文书
授权收款委托书
2014/09/23 职场文书
初中生散播谣言检讨书
2014/11/17 职场文书
毕业答辩开场白范文
2015/05/27 职场文书