开发一个简单的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 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) 从这个公式来看,应该先匹配到(-40/5),将这个括号里的公式进行计算,计算后将内容把(-40/5)替换掉,依次类推,将所有的括号都进行这样的计算与替换,在计算括号里的公式的时候需要注意的问题应该先匹配乘除进行计算与替换直到公式中没有乘除,然后再匹配加减进行计算与替换,直到匹配不到加减,这样最后的结果就是首先将括号里的内容计算并匹配,得到了一个只存在加减乘除的公式,这个时候和计算括号里的公式的方法一样,先匹配乘除计算并替换,然后匹配加减计算并替换,这样最后就能计算得出答案。

下列代码是整个的实现过程:注意:下面的代码并没有对输入公式的正确进行判断,但是已经实现了如果输入正确的公式都能正常计算

import re
#匹配整数或小数的乘除法,包括了开头存在减号的情况
mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\.\d+)?")
#匹配整数或小数的加减法,包括了开头存在减号的情况
plus_minus = re.compile("(-?\d+)(\.\d+)?(-|\+)(-?\d+)(\.\d+)?")
#匹配括号
bracket=re.compile("\([^()]*\)")
#匹配乘法的时候出现乘以负数的情况,包括了开头存在减号的情况
mul_minus_minus = re.compile("(-?\d+)(\.\d+)?(\*-)(\d+)(\.\d+)?")
#匹配除法的时候出现乘以负数的情况,包括了开头存在减号的情况
div_minus_minus = re.compile("(-?\d+)(\.\d+)?(/-)(\d+)(\.\d+)?") #定义一个两位数的加减乘除法的运算,匹配左边的右边的数字和左边的数字,然后进行计算
def touble_cale(str_expire):
if str_expire.count("+") == 1:
right_num = float(str_expire[(str_expire.find("+")+1):])
left_num = float(str_expire[:str_expire.find("+")])
return str(right_num+left_num)
elif str_expire[1:].count("-") == 1:
right_num = float(str_expire[:str_expire.find("-",1)])
left_num = float(str_expire[(str_expire.find("-", 1) + 1):])
return str(right_num - left_num)
elif str_expire.count("*") == 1:
right_num = float(str_expire[:str_expire.find("*")])
left_num = float(str_expire[(str_expire.find("*")+1):])
return str(right_num * left_num)
elif str_expire.count("/") == 1:
right_num = float(str_expire[:str_expire.find("/")])
left_num = float(str_expire[(str_expire.find("/") + 1):])
return str(right_num / left_num) #定义一个方法用于判断是否存在乘以负数和除以负数的情况
def judge_mul_minus(str_expire):
#判断公式中乘以负数的部分
if len(re.findall("(\*-)", str_expire)) != 0:
#调用上面的正则取得*-的公式
temp_mul_minus = mul_minus_minus.search(str_expire).group()
#将匹配的部分的*-换成*并将-放到前面
temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*"))
#经更改的的部分与原来的部分进行替换
str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2)
return judge_mul_minus(str_expire)
#return str_expire
# 判断公式中除以负数的部分
elif len(re.findall(r"(/-)", str_expire)) != 0:
# 调用上面的正则取得/-的公式
temp_dev_minus = div_minus_minus.search(str_expire).group()
# 将匹配的部分的/-换成/并将-放到前面
temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/"))
# 经更改的的部分与原来的部分进行替换
str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2)
return judge_mul_minus(str_expire)
#调用change_sign将公式中的++换成= +-换成-
return change_sign(str_expire) #定义一个方法取将--更改为+ +-改为-
def change_sign(str_expire):
if len(re.findall(r"(\+-)", str_expire)) != 0:
str_expire = str_expire.replace("+-", "-")
return change_sign(str_expire)
elif len(re.findall(r"(--)", str_expire)) != 0:
str_expire = str_expire.replace("--", "+")
return change_sign(str_expire)
return str_expire #定义一个方法用于计算只有加减乘除的公式,优先处理乘法
def cale_mix(str_expire):
#如果公式中出现符号数字的情况即+5 -6 *8 /8的这种情况直接放回数字否则则先计算乘除在处理加减
while len(re.findall("[-+*/]",str_expire[1:])) != 0:
if len(re.findall("(\*|/)",str_expire)) != 0:
str_expire = str_expire.replace(mul_div.search(str_expire).group(),touble_cale(mul_div.search(str_expire).group()))
elif len(re.findall("(\+|-)",str_expire)) !=0:
str_expire = str_expire.replace(plus_minus.search(str_expire).group(),touble_cale(plus_minus.search(str_expire).group()))
return str_expire #定义一个方法用于去括号,并调用上述的方法进行计算
def remove_bracket(str_expire):
#判断公式中是否有括号
if len(bracket.findall(str_expire)) == 0:
return cale_mix(judge_mul_minus(str_expire))
elif len(bracket.findall(str_expire))!=0:
while len(bracket.findall(str_expire)) !=0:
#print(bracket.search(str_expire).group())
#只有存在括号优先处理括号中的内容并对内容进行替换,直到没有括号位置
str_expire = str_expire.replace(bracket.search(str_expire).group(),cale_mix(judge_mul_minus(bracket.search(str_expire).group()[1:-1])))
str_expire = cale_mix(judge_mul_minus(str_expire))
return str_expire if __name__ == "__main__":
while True:
user_input_expire = input("请输入你的公式:(不要带空格,q表示退出):")
print("%s=%s" %(user_input_expire,remove_bracket(user_input_expire)))
continue

  

下面将代码进行分析:

首先是用写正则,一次匹配乘除法的正则,但是写的时候需要注意正则前面哟一个"-?",表示匹配乘除的时候需要匹配前面的减号。同样类似的方法匹配加减法,

然后是匹配括号,这个也是整个过程中非常重要的一个地方:bracket=re.compile("\([^()]*\)")

接着是匹配乘以负数的情况已经除以负数的情况

#匹配整数或小数的乘除法,包括了开头存在减号的情况
mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\.\d+)?")
#匹配整数或小数的加减法,包括了开头存在减号的情况
plus_minus = re.compile("(-?\d+)(\.\d+)?(-|\+)(-?\d+)(\.\d+)?")
#匹配括号
bracket=re.compile("\([^()]*\)")
#匹配乘法的时候出现乘以负数的情况,包括了开头存在减号的情况
mul_minus_minus = re.compile("(-?\d+)(\.\d+)?(\*-)(\d+)(\.\d+)?")
#匹配除法的时候出现乘以负数的情况,包括了开头存在减号的情况
div_minus_minus = re.compile("(-?\d+)(\.\d+)?(/-)(\d+)(\.\d+)?")

  

接着下面的这个方法是用于匹配两位数的四则运算

#定义一个两位数的加减乘除法的运算,匹配左边的右边的数字和左边的数字,然后进行计算
def touble_cale(str_expire):
if str_expire.count("+") == 1:
right_num = float(str_expire[(str_expire.find("+")+1):])
left_num = float(str_expire[:str_expire.find("+")])
return str(right_num+left_num)
elif str_expire[1:].count("-") == 1:
right_num = float(str_expire[:str_expire.find("-",1)])
left_num = float(str_expire[(str_expire.find("-", 1) + 1):])
return str(right_num - left_num)
elif str_expire.count("*") == 1:
right_num = float(str_expire[:str_expire.find("*")])
left_num = float(str_expire[(str_expire.find("*")+1):])
return str(right_num * left_num)
elif str_expire.count("/") == 1:
right_num = float(str_expire[:str_expire.find("/")])
left_num = float(str_expire[(str_expire.find("/") + 1):])
return str(right_num / left_num)

  

这个方法是用于判断存在乘以负数的时候和除以负数的情况如何处理,这里的操作是将负号放到公式的前面,然后将公式中的*-和/-都换成*和/

#定义一个方法用于判断是否存在乘以负数和除以负数的情况
def judge_mul_minus(str_expire):
#判断公式中乘以负数的部分
if len(re.findall("(\*-)", str_expire)) != 0:
#调用上面的正则取得*-的公式
temp_mul_minus = mul_minus_minus.search(str_expire).group()
#将匹配的部分的*-换成*并将-放到前面
temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*"))
#经更改的的部分与原来的部分进行替换
str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2)
return judge_mul_minus(str_expire)
#return str_expire
# 判断公式中除以负数的部分
elif len(re.findall(r"(/-)", str_expire)) != 0:
# 调用上面的正则取得/-的公式
temp_dev_minus = div_minus_minus.search(str_expire).group()
# 将匹配的部分的/-换成/并将-放到前面
temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/"))
# 经更改的的部分与原来的部分进行替换
str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2)
return judge_mul_minus(str_expire)
#调用change_sign将公式中的++换成= +-换成-
return change_sign(str_expire)

  

下面的方法用于将公式中可能会出现++和--的情况,将其替换为++替换为+将--替换为+

#定义一个方法取将--更改为+ +-改为-
def change_sign(str_expire):
if len(re.findall(r"(\+-)", str_expire)) != 0:
str_expire = str_expire.replace("+-", "-")
return change_sign(str_expire)
elif len(re.findall(r"(--)", str_expire)) != 0:
str_expire = str_expire.replace("--", "+")
return change_sign(str_expire)
return str_expire

  

这个方法用于处理括号里面的四则运算以及整个公式没有括号,只剩下四则运算的情况,优先匹配乘除计算,如果没有乘除了匹配加减进行计算

#定义一个方法用于计算只有加减乘除的公式,优先处理乘法
def cale_mix(str_expire):
#如果公式中出现符号数字的情况即+5 -6 *8 /8的这种情况直接放回数字否则则先计算乘除在处理加减
while len(re.findall("[-+*/]",str_expire[1:])) != 0:
if len(re.findall("(\*|/)",str_expire)) != 0:
str_expire = str_expire.replace(mul_div.search(str_expire).group(),touble_cale(mul_div.search(str_expire).group()))
elif len(re.findall("(\+|-)",str_expire)) !=0:
str_expire = str_expire.replace(plus_minus.search(str_expire).group(),touble_cale(plus_minus.search(str_expire).group()))
return str_expire

  

下面的方法用于匹配括号用,匹配到括号后调用上面的方法进行计算和替换,直到整个公式计算完毕

#定义一个方法用于去括号,并调用上述的方法进行计算
def remove_bracket(str_expire):
#判断公式中是否有括号
if len(bracket.findall(str_expire)) == 0:
return cale_mix(judge_mul_minus(str_expire))
elif len(bracket.findall(str_expire))!=0:
while len(bracket.findall(str_expire)) !=0:
#print(bracket.search(str_expire).group())
#只有存在括号优先处理括号中的内容并对内容进行替换,直到没有括号位置
str_expire = str_expire.replace(bracket.search(str_expire).group(),cale_mix(judge_mul_minus(bracket.search(str_expire).group()[1:-1])))
str_expire = cale_mix(judge_mul_minus(str_expire))
return str_expire
if __name__ == "__main__":
while True:
user_input_expire = input("请输入你的公式:(不要带空格,q表示退出):")
print("%s=%s" %(user_input_expire,remove_bracket(user_input_expire)))
continue

  

python之计算器的更多相关文章

  1. 从零开始学习PYTHON3讲义(二)把Python当做计算器

    <从零开始PYTHON3>第二讲 上一讲我们说过了如何启动Python IDLE集成开发学习环境,macOS/Linux都可以在命令行执行idle3.Windows则从开始菜单中去寻找ID ...

  2. python实现计算器

    计算器功能 实现优先级解析,加减乘除四则运算 自定义小数位精度 实现思想: 先找到最里层括号,根据乘除,加减优先级,调用写好的乘除.加减运算函数算出括号内总值,再将原括号式用所得值替换,此过程循环进行 ...

  3. python之计算器(第四天)

    作业: 使用正则表达式和递归实现计算器功能. 实现: 1.实现带括号的计算 2.实现指数.加减乘除求余等功能 一.实例说明: 本实例自己写了个版本,但依旧存在一点bug,例:-2-2等计算问题,故最后 ...

  4. 利用PYTHON设计计算器功能

    通过利用PYTHON 设计处理计算器的功能如: 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 ))- (-4*3 ...

  5. Python科学计算器(计算器)

    说明 该计算器主要是为了练习正则表达式以及python基础所写:代码比较low! 运行过程 请输入你的计算公式, 计算器会将计算结果输出到屏幕上(此处会打印步骤); 退出(exit/quit) MyC ...

  6. Python数学运算入门把Python当作计算器

    让我们尝试一些简单的 Python 命令.启动解释器,等待界面中的提示符,>>> (这应该花不了多少时间). 3.1.1. 数字 解释器就像一个简单的计算器一样:你可以在里面输入一个 ...

  7. [IT学习]转载python 项目 计算器

    这个是从网上搜到的Python小项目之计算器(原文地址:http://www.2cto.com/kf/201402/279637.html).但该段代码估计是Python 2 写的. 如果你使用的程序 ...

  8. python编写计算器

    程序代码 # coding: utf-8# 将tkinter改为Tkinter兼容Python 2.xfrom tkinter import *class App: def __init__(self ...

  9. python写计算器

    #!/usr/bin/env python # -*- coding:utf-8 -*- import re def chu(arg1): #定义加减 arg = arg1[0] #beacuse p ...

随机推荐

  1. 内核blackhole

    1) 当arp表项不存在的时候,数据包等待表项存在了再发,还是直接把数据包给丢掉; 2)如果网络目的地址不可达,是在那一层把数据丢弃,再是路由层就判断还是arp层呢?

  2. RT-thread内核之线程调度器

    一.前言 RT-Thread中提供的线程调度器是基于全抢占式优先级的调度,在系统中除了中断处理函数.调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自 ...

  3. 【bzoj5089】最大连续子段和 分块+单调栈维护凸包

    题目描述 给出一个长度为 n 的序列,要求支持如下两种操作: A  l  r  x :将 [l,r] 区间内的所有数加上 x : Q  l  r : 询问 [l,r] 区间的最大连续子段和. 其中,一 ...

  4. POJ1651:Multiplication Puzzle——题解

    http://poj.org/problem?id=1651 题目大意:同“乘法游戏”,这里将乘法游戏的题面复制过来. 乘法游戏是在一行牌上进行的.每一张牌包括了一个正整数.在每一个移动中,玩家拿出一 ...

  5. BZOJ4003:[JLOI2015]城池攻占——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4003 https://www.luogu.org/problemnew/show/P3261 小铭 ...

  6. BZOJ1878:[SDOI2009]HH的项链——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1878 题面源于洛谷 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的 ...

  7. HUD.2544 最短路 (Dijkstra)

    HUD.2544 最短路 (Dijkstra) 题意分析 1表示起点,n表示起点(或者颠倒过来也可以) 建立无向图 从n或者1跑dij即可. 代码总览 #include <bits/stdc++ ...

  8. React setState和修改props触发的钩子

    1. setState的改变会触发4个生命周期钩子 shouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 2. props的 ...

  9. 【HASH】【UVA 10125】 Sumset

    传送门 Description 给定一个整数集合S,求一个最大的d,满足a+b+c=d,其中a,b,c,d∈S Input 多组数据,每组数据包括: 第一行一个整数n,代表元素个数 下面n行每行一个整 ...

  10. 【优先队列】【UVa11997】K Smallest Sums

    传送门 Description Input Output Translation · 给定k个长度为k的数组,把每个数组选一个元素加起来,这样共有kk种可能的答案,求最小的k个 Sample Inpu ...