作业需求:

开发一个简单的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-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))类似的公式计算的更多相关文章

  1. 正则表达式计算 origin = "1 - 2 * ( ( 60 - 30 + ( -40.0 / 5 ) * ( 9 - 2 * 5 / 3 + 7 / 3 * 99 / 4 * 2998 + 10 * 568 / 14 )) - ( - 4 * 3 ) / ( 16 - 3 * 2))"

    #!/usr/bin/env python import re def f1(arg): return 1 origin = "1 - 2 * ( ( 60 - 30 + ( -40.0 / ...

  2. [转]Python程序员必须知道的30条编程技巧

    30 tips & tricks for Python Programming 1  直接交换两个数字位置 x, y = 10, 20 print(x, y) x, y = y, x prin ...

  3. WPF实现强大的动态公式计算

    数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题. 1.VS2012新建一个WPF应用程序WpfApp ...

  4. c语言详解  蔡勒(Zeller)公式计算某一天是星期几  极其方便

    —— 蔡勒(Zeller)公式 ,小于等于14,即在蔡勒公式中,某年的1.2月要看作上一年的13.14月来计算,比如2003年1月1日要看作2002年的13月1日来计算):d:日:[ ]代表取整,即只 ...

  5. 使用Machin公式计算

    使用Machin公式计算,并使用百亿进制+末项位数控制,这里可算出数万位(比最简PI快80倍),源代码约40行,在本网页中. 计算公式 PI=16arctg(1/5)-4arctg(1/239),其中 ...

  6. Windows API方式直接调用C#的DLL,支持多音字转拼音、Gzip解压缩、公式计算(VBA、C++、VB、Delphi甚至java都可以)

    原始链接 https://www.cnblogs.com/Charltsing/p/DllExport.html 这两年,我在VBA应用方面一直有几大痛点:1.多音字转拼音:2.64位下的GZIP解压 ...

  7. Codeforces Round #532 (Div. 2)- C(公式计算)

    NN is an experienced internet user and that means he spends a lot of time on the social media. Once ...

  8. 【Zeller公式计算星期几】HDU 6112 今夕何夕

    acm.hdu.edu.cn/showproblem.php?pid=6112 [思路] 公式计算即可,注意特判2月29号 Zeller公式里,计算出的week不能直接模7,要保证week是正数 [A ...

  9. C语言:根据以下公式计算s,s=1+1/(1+2)+1/(1+2+3)+...+1/(1+2+3+...+n) -在形参s所指字符串中寻找与参数c相同的字符,并在其后插入一个与之相同的字符,

    //根据一下公式计算s,并将计算结果作为函数返回值,n通过形参传入.s=1+1/(1+2)+1/(1+2+3)+...+1/(1+2+3+...+n) #include <stdio.h> ...

随机推荐

  1. Channel

    提起Channel,JDK的NIO类库的重要组成部分,就是提供了java.nio.SocketChannel和java.nio.ServerSocketChannel,用于非阻塞的I/O操作. 类似于 ...

  2. 破解压缩文件密码rarcrack

    破解压缩文件密码rarcrack   常见的压缩文件格式有ZIP.RAR和7z.这三种格式都支持使用密码进行加密压缩.前面讲过破解ZIP压缩文件,可以使用fcrackzip.对于RAR和7z格式,可以 ...

  3. [我的试题]Test of String

    1.前言 这是我出的第一套题目,话说感觉有点晚了,还是在向总安排下出的.我被安排的是字符串方面的内容,这应该相对而言是比较小众的知识点吧,但是一样的有作用的,也有很神的题目.所谓是NOIP模拟题,其实 ...

  4. 【水】基于ege的2048

    不要问我ege怎么装 http://tieba.baidu.com/p/2227018541 好,现在我们装好了ege 开始写2048吧 没有算法,单纯模拟,不用讲解——这才叫[水]的含义 界面极度简 ...

  5. 淘宝弹性布局方案lib-flexible实践

    2个月前,写过一篇文章<从网易与淘宝的font-size思考前端设计稿与工作流>总结过一些移动web中有关手机适配的一些思路,当时也是因为工作的关系分析了下网易跟淘宝的移动页面,最后才有那 ...

  6. python字典

    1.字典解释 映射:通过名字来引用值得数据结构,字典是python中唯一内建的映射类型,字典中的值并没有特殊的顺序,都存储在一个特定的键下,键可以使数字.字符串.元组,通过查找某个特定键,就可以找到对 ...

  7. python学习 第一天

    正式学习python第一天,网上找到了python教程,带练习题的,又装了ubuntu. 这是学习笔记: list[]: 可变,append/1,insert/2,pop/index? tuple() ...

  8. Unity3D DFGUI根据名称获取多个子控件代码

    dfPanel control = gameObject.GetComponent<dfPanel>(); dfLabel avatarName = control.Find<dfL ...

  9. CSS Sprites+CSS3 Icon Font

    CSS Sprites+CSS3 Icon Font CSS Sprites在国内很多人叫CSS精灵,是一种网页图片应用处理方式.它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来, ...

  10. 服务器中配置多个Tomcat及内存溢出配置

    1.更改server.xml文件中端口(启动.关闭端口) 2.在startup.bat文件开头加上 SET JAVA_HOME=C:\Program Files (x86)\Java\jdk1.8.0 ...