用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 条评论
登录 后参与评论

相关文章

来自专栏大闲人柴毛毛

动态规划法(三)——最长公共子序列

问题描述 给定两个序列,求出它们的最长公共子序列。 如:序列X={a,b,c,b,d,a,b},Y={b,d,c,a,b,a},则X和Y的最长公共子...

3194
来自专栏King_3的技术专栏

leetcode-151-翻转字符串里的单词

1、这道题给定一个字符串s,相当于一个英文句子,要求把这个句子中的单词反转一下,后面的要放在前面,前面放在后面。

1591
来自专栏Python小屋

详解Python中的生成器表达式(generator expression)

生成器表达式(generator expression)也叫生成器推导式或生成器解析式,用法与列表推导式非常相似,在形式上生成器推导式使用圆括号(parenth...

3416
来自专栏我是攻城师

理解计数排序算法的原理和实现

计数排序(Counting sort)是一种稳定的线性时间排序算法,其平均时间复杂度和空间复杂度为O(n+k),其中n为数组元素的个数,k为待排序数组里面的最大...

451
来自专栏Fred Liang

Numpy

对数组运算相当于对数组每一个元素进行运算 a = np.arange(24).reshape((2,3,4))

782
来自专栏人工智能LeadAI

为什么算法容易忘记之插入排序

在学习常用的排序算法时,常有这样的感觉,一看就懂,过眼就忘。原因在于没有将排序的基本思想与代码中各个循环控制变量的意义联系起来进行理解记忆。 插入排序 首先,我...

3425
来自专栏HTML5学堂

提取数字——字符串、正则面试题

提取数字——字符串、正则面试题 HTML5学堂:正则、数组、字符串,是JavaScript语言中让人头痛的一些知识,今天这篇文章我们使用数组字符串、正则两种方法...

2786
来自专栏老马说编程

(45) 神奇的堆 / 计算机程序的思维逻辑

前面几节介绍了Java中的基本容器类,每个容器类背后都有一种数据结构,ArrayList是动态数组,LinkedList是链表,HashMap/HashSet是...

2019
来自专栏武培轩的专栏

剑指Offer-调整数组顺序使奇数位于偶数前面

题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶...

3456
来自专栏null的专栏

数据结构和算法——二叉排序树

一、二叉排序树 对于无序的序列“62,58,88,47,73,99,35,51,93,29,37,49,56,36,48,50”,是否存在一种高效的查找方案,使...

3296

扫码关注云+社区