用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判断Abundant Number的方法
Jun 15 Python
Python算法应用实战之栈详解
Feb 04 Python
python paramiko模块学习分享
Aug 23 Python
Python读取图片为16进制表示简单代码
Jan 19 Python
python实现求解列表中元素的排列和组合问题
Mar 15 Python
Python使用xlwt模块操作Excel的方法详解
Mar 27 Python
Tensorflow 同时载入多个模型的实例讲解
Jul 27 Python
python如何实现单链表的反转
Feb 10 Python
Python导入模块包原理及相关注意事项
Mar 25 Python
Python pip使用超时问题解决方案
Aug 03 Python
Python+Opencv实现把图片、视频互转的示例
Dec 17 Python
Python requests用法和django后台处理详解
Mar 19 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
在项目中寻找代码的坏命名
2012/07/14 PHP
解析php curl_setopt 函数的相关应用及介绍
2013/06/17 PHP
php文件上传类的分享
2017/07/06 PHP
jquery插件开发方法(初学者)
2012/02/03 Javascript
jquery实现的随机多彩tag标签随机颜色和字号大小效果
2014/03/27 Javascript
纯JavaScript实现获取onclick、onchange等事件的值
2014/12/29 Javascript
Javascript 拖拽雏形中的一些问题(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
javascript的几种继承方法介绍
2016/03/22 Javascript
jQuery 实现ajax传入参数含有特殊字符的方法总结
2016/10/17 Javascript
Bootstrap导航条学习使用(二)
2017/02/08 Javascript
详解用node-images 打造简易图片服务器
2017/05/08 Javascript
详解react-webpack2-热模块替换[HMR]
2017/08/03 Javascript
Vue项目组件化工程开发实践方案
2018/01/09 Javascript
快速解决vue-cli在ie9+中无效的问题
2018/09/04 Javascript
微信小程序实现页面分享onShareAppMessage
2019/08/12 Javascript
原生js实现下拉选项卡
2019/11/27 Javascript
[22:07]DOTA2-DPC中国联赛 正赛 iG vs Magma 选手采访
2021/03/11 DOTA
Python警察与小偷的实现之一客户端与服务端通信实例
2014/10/09 Python
Python实现读取TXT文件数据并存进内置数据库SQLite3的方法
2017/08/08 Python
Python安装Flask环境及简单应用示例
2019/05/03 Python
10 行Python 代码实现 AI 目标检测技术【推荐】
2019/06/14 Python
python快速排序的实现及运行时间比较
2019/11/22 Python
Python实现图片添加文字
2019/11/26 Python
HTML5 Canvas阴影使用方法实例演示
2013/08/02 HTML / CSS
abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
2012/10/15 面试题
技术经理的自我评价范文
2013/12/03 职场文书
工程专业毕业生自荐信范文
2013/12/25 职场文书
自我鉴定三原则
2014/01/13 职场文书
银行实习生的自我评价
2014/01/13 职场文书
舞蹈教育学专业求职信
2014/06/29 职场文书
竞聘报告优秀范文
2014/11/06 职场文书
研究生给导师的自荐信
2015/03/06 职场文书
行政处罚告知书
2015/07/01 职场文书
解决redis sentinel 频繁主备切换的问题
2021/04/12 Redis
Redis+Lua脚本实现计数器接口防刷功能(升级版)
2022/02/12 Redis
python中 Flask Web 表单的使用方法
2022/05/20 Python