用python实现计算1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))类似的公式计算

作业需求:

开发一个简单的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)替换掉,依次类推,将所有的括号都进行这样的计算与替换,在计算括号里的公式的时候需要注意的问题应该先匹配乘除进行计算与替换直到公式中没有乘除,然后再匹配加减进行计算与替换,直到匹配不到加减,这样最后的结果就是首先将括号里的内容计算并匹配,得到了一个只存在加减乘除的公式,这个时候和计算括号里的公式的方法一样,先匹配乘除计算并替换,然后匹配加减计算并替换,这样最后就能计算得出答案。

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

 1 import re
 2 #匹配整数或小数的乘除法,包括了开头存在减号的情况
 3 mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\.\d+)?")
 4 #匹配整数或小数的加减法,包括了开头存在减号的情况
 5 plus_minus = re.compile("(-?\d+)(\.\d+)?(-|\+)(-?\d+)(\.\d+)?")
 6 #匹配括号
 7 bracket=re.compile("\([^()]*\)")
 8 #匹配乘法的时候出现乘以负数的情况,包括了开头存在减号的情况
 9 mul_minus_minus = re.compile("(-?\d+)(\.\d+)?(\*-)(\d+)(\.\d+)?")
10 #匹配除法的时候出现乘以负数的情况,包括了开头存在减号的情况
11 div_minus_minus = re.compile("(-?\d+)(\.\d+)?(/-)(\d+)(\.\d+)?")
12 
13 
14 #定义一个两位数的加减乘除法的运算,匹配左边的右边的数字和左边的数字,然后进行计算
15 def touble_cale(str_expire):
16     if str_expire.count("+") == 1:
17         right_num = float(str_expire[(str_expire.find("+")+1):])
18         left_num = float(str_expire[:str_expire.find("+")])
19         return str(right_num+left_num)
20     elif str_expire[1:].count("-") == 1:
21         right_num = float(str_expire[:str_expire.find("-",1)])
22         left_num = float(str_expire[(str_expire.find("-", 1) + 1):])
23         return str(right_num - left_num)
24     elif str_expire.count("*") == 1:
25         right_num = float(str_expire[:str_expire.find("*")])
26         left_num = float(str_expire[(str_expire.find("*")+1):])
27         return str(right_num * left_num)
28     elif str_expire.count("/") == 1:
29         right_num = float(str_expire[:str_expire.find("/")])
30         left_num = float(str_expire[(str_expire.find("/") + 1):])
31         return str(right_num / left_num)
32 
33 
34 #定义一个方法用于判断是否存在乘以负数和除以负数的情况
35 def judge_mul_minus(str_expire):
36     #判断公式中乘以负数的部分
37     if len(re.findall("(\*-)", str_expire)) != 0:
38         #调用上面的正则取得*-的公式
39         temp_mul_minus = mul_minus_minus.search(str_expire).group()
40         #将匹配的部分的*-换成*并将-放到前面
41         temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*"))
42         #经更改的的部分与原来的部分进行替换
43         str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2)
44         return judge_mul_minus(str_expire)
45         #return str_expire
46     # 判断公式中除以负数的部分
47     elif len(re.findall(r"(/-)", str_expire)) != 0:
48         # 调用上面的正则取得/-的公式
49         temp_dev_minus = div_minus_minus.search(str_expire).group()
50         # 将匹配的部分的/-换成/并将-放到前面
51         temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/"))
52         # 经更改的的部分与原来的部分进行替换
53         str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2)
54         return judge_mul_minus(str_expire)
55     #调用change_sign将公式中的++换成= +-换成-
56     return change_sign(str_expire)
57 
58 #定义一个方法取将--更改为+ +-改为-
59 def change_sign(str_expire):
60     if len(re.findall(r"(\+-)", str_expire)) != 0:
61         str_expire = str_expire.replace("+-", "-")
62         return change_sign(str_expire)
63     elif len(re.findall(r"(--)", str_expire)) != 0:
64         str_expire = str_expire.replace("--", "+")
65         return change_sign(str_expire)
66     return str_expire
67 
68 
69 #定义一个方法用于计算只有加减乘除的公式,优先处理乘法
70 def cale_mix(str_expire):
71     #如果公式中出现符号数字的情况即+5  -6 *8  /8的这种情况直接放回数字否则则先计算乘除在处理加减
72     while len(re.findall("[-+*/]",str_expire[1:])) != 0:
73         if len(re.findall("(\*|/)",str_expire)) != 0:
74             str_expire = str_expire.replace(mul_div.search(str_expire).group(),touble_cale(mul_div.search(str_expire).group()))
75         elif len(re.findall("(\+|-)",str_expire)) !=0:
76             str_expire = str_expire.replace(plus_minus.search(str_expire).group(),touble_cale(plus_minus.search(str_expire).group()))
77     return str_expire
78 
79 #定义一个方法用于去括号,并调用上述的方法进行计算
80 def remove_bracket(str_expire):
81     #判断公式中是否有括号
82     if len(bracket.findall(str_expire)) == 0:
83         return cale_mix(judge_mul_minus(str_expire))
84     elif len(bracket.findall(str_expire))!=0:
85         while len(bracket.findall(str_expire)) !=0:
86             #print(bracket.search(str_expire).group())
87             #只有存在括号优先处理括号中的内容并对内容进行替换,直到没有括号位置
88             str_expire = str_expire.replace(bracket.search(str_expire).group(),cale_mix(judge_mul_minus(bracket.search(str_expire).group()[1:-1])))
89         str_expire = cale_mix(judge_mul_minus(str_expire))
90         return str_expire
91 
92 
93 if __name__ == "__main__":
94     while True:
95         user_input_expire = input("请输入你的公式:(不要带空格,q表示退出):")
96         print("%s=%s" %(user_input_expire,remove_bracket(user_input_expire)))
97         continue

下面将代码进行分析:

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

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

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

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

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

 1 #定义一个两位数的加减乘除法的运算,匹配左边的右边的数字和左边的数字,然后进行计算
 2 def touble_cale(str_expire):
 3     if str_expire.count("+") == 1:
 4         right_num = float(str_expire[(str_expire.find("+")+1):])
 5         left_num = float(str_expire[:str_expire.find("+")])
 6         return str(right_num+left_num)
 7     elif str_expire[1:].count("-") == 1:
 8         right_num = float(str_expire[:str_expire.find("-",1)])
 9         left_num = float(str_expire[(str_expire.find("-", 1) + 1):])
10         return str(right_num - left_num)
11     elif str_expire.count("*") == 1:
12         right_num = float(str_expire[:str_expire.find("*")])
13         left_num = float(str_expire[(str_expire.find("*")+1):])
14         return str(right_num * left_num)
15     elif str_expire.count("/") == 1:
16         right_num = float(str_expire[:str_expire.find("/")])
17         left_num = float(str_expire[(str_expire.find("/") + 1):])
18         return str(right_num / left_num)

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

 1 #定义一个方法用于判断是否存在乘以负数和除以负数的情况
 2 def judge_mul_minus(str_expire):
 3     #判断公式中乘以负数的部分
 4     if len(re.findall("(\*-)", str_expire)) != 0:
 5         #调用上面的正则取得*-的公式
 6         temp_mul_minus = mul_minus_minus.search(str_expire).group()
 7         #将匹配的部分的*-换成*并将-放到前面
 8         temp_mul_minus_2 = temp_mul_minus.replace(temp_mul_minus,"-" + temp_mul_minus.replace("*-","*"))
 9         #经更改的的部分与原来的部分进行替换
10         str_expire=str_expire.replace(temp_mul_minus,temp_mul_minus_2)
11         return judge_mul_minus(str_expire)
12         #return str_expire
13     # 判断公式中除以负数的部分
14     elif len(re.findall(r"(/-)", str_expire)) != 0:
15         # 调用上面的正则取得/-的公式
16         temp_dev_minus = div_minus_minus.search(str_expire).group()
17         # 将匹配的部分的/-换成/并将-放到前面
18         temp_dev_minus_2 = temp_dev_minus.replace(temp_dev_minus,"-" + temp_dev_minus.replace("/-","/"))
19         # 经更改的的部分与原来的部分进行替换
20         str_expire = str_expire.replace(temp_dev_minus,temp_dev_minus_2)
21         return judge_mul_minus(str_expire)
22     #调用change_sign将公式中的++换成= +-换成-
23     return change_sign(str_expire)

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

1 #定义一个方法取将--更改为+ +-改为-
2 def change_sign(str_expire):
3     if len(re.findall(r"(\+-)", str_expire)) != 0:
4         str_expire = str_expire.replace("+-", "-")
5         return change_sign(str_expire)
6     elif len(re.findall(r"(--)", str_expire)) != 0:
7         str_expire = str_expire.replace("--", "+")
8         return change_sign(str_expire)
9     return str_expire

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

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C语言及其他语言

C语言中的基本输入输出

1.字符输出函数putchar putchar函数是字符输出函数,其功能是在终端(显示器)输出单个字符。其一般调用形式为: putchar(字符变量); ...

2789
来自专栏运维技术迷

连仕彤博客[Python笔记] Python3增加的关键字nonlocal

1646
来自专栏数据结构与算法

P3368 【模板】树状数组 2(树状数组维护差分序列)

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N、M,...

3226
来自专栏python学习指南

python字符串操作

本篇文章将介绍python的字符串操作,更多内容请参考:python学习指南 一、查看帮助文档 在学习编程语言过程中,不管是python语言还是其它语言时...

19910
来自专栏CDA数据分析师

工具 | Python集合使用详解

我会在这篇文章介绍Python几种类型的集合。 在开始前,先定义集合是什么。一个集合就像篮子,你可以放进和取出东西,可以是同一类的东西,也可以是不同类的。基本上...

1895
来自专栏郭耀华‘s Blog

Java Arrays工具类的使用

Arrays 类 java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。具有以下功能: 给数组赋值:通过fill方法。 对数组...

3248
来自专栏緣來來來

Python爬虫--- 1.4 正则表达式:re库

这里其实就是一个非常简单的删除当前目录下所有txt文件的命令, *号其实就一个 ‘通配符’。表示任何形式的数据。 从这里我们就可以引出正则表达式的概念:

341
来自专栏desperate633

Java中String通过引用传递问题详细解析

This is a classic question of Java. Many similar questions have been asked on st...

611
来自专栏JAVA技术站

shell学习二数组 原

类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。

381
来自专栏软件开发 -- 分享 互助 成长

谈谈 char *num="123";和char num[4]="123";的区别

最近写程序的时候发现这样一个问题 #include<iostream> #include <string.h> using namespace std; vo...

1728

扫码关注云+社区