内容简介:day4 计算器
作业:计算器开发
(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) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式,运算后得出结果,结果必须与真实的计算器所得出的结果一致。
代码如下:
1 import re
2
3 formula = '1 - 2 * ( (60-30 +(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )'
4 #formula = "(1++1)"
5 def modify(formula_deep):
6 '''程序修饰函数,去除空格和括号'''
7 '''去除运算中出现的+- -- ++ -+ 等情形'''
8 formula_deep = re.sub("[() ]","",formula_deep) #替换空格和空号
9 formula_deep = re.sub("\+-","-",formula_deep) #替换+-为-
10 formula_deep = re.sub("--",'+',formula_deep) #替换--为+
11 formula_deep = re.sub("-\+",'-',formula_deep)
12 formula_deep = re.sub("\++","+",formula_deep)
13 return formula_deep
14
15 def multiply_divide(formula_deep):
16 '''计算乘除'''
17 '''由于乘除是首先计算的,我们的思路是,首先计算乘除,然后把计算的结果替换进去,就可以得到只剩加减的情形'''
18 calc_sign = re.findall("[+-]",formula_deep) #提取字符串中所有的加减号
19 calc_list = re.split("[+-]",formula_deep) #以加减号进行分割,得到乘除
20 '''由于我们得到的calc_list:['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14'],里面由于-号引起的麻烦,-9被分割了,2*5/等'''
21 if calc_list[0] == '':
22 '''处理列表开头“”空的情况,说明这里是负数,被我们分割掉了要重新进行合并'''
23 calc_list[1] = calc_sign[0] + calc_list[1]
24 del calc_sign[0]
25 del calc_list[0]
26 for num,line in enumerate(calc_list):
27 '''处理2*5/的情形,说明这种后面除的是一个负数,因为只有负数才会出现这种情况2*5/-3被分割了,需要合并'''
28 if line.endswith("/") or line.endswith("*"):
29 '''如果结尾包括乘除号,说明是负数被拆分了'''
30 calc_list[num+1] = calc_list[num] + calc_sign[num] + calc_list[num+1]
31 del calc_sign[num]
32 del calc_list[num]
33 '''下面进行乘除的正式运算,上面都是进行格式转换'''
34 for index,string in enumerate(calc_list):
35 '''首先提取编号,便于后面替换运算出来的值'''
36 if "/" in string or "*" in string:
37 mul_div_sign = re.findall("[/*]",string)
38 mul_div_list = re.split("[/*]",string)
39 calc_value = None
40 for e_index,e in enumerate(mul_div_list):
41 if calc_value:
42 if mul_div_sign[e_index-1] == "/":
43 calc_value /= float(e)
44 elif mul_div_sign[e_index-1] == "*":
45 calc_value *= float(e)
46 else:
47 calc_value = float(e)
48 calc_list[index] = calc_value
49 else:
50 pass
51 '''计算值'''
52 value = None
53 for k,v in enumerate(calc_list):
54 '''计算加减的情况'''
55 if value:
56 if calc_sign[k-1] == "-":
57 value -= float(v)
58 elif calc_sign[k-1] == '+':
59 value += float(v)
60 else:
61 value = float(v)
62 return value
63
64
65 def main(formula):
66 '''程序主入口,生成带括号的情况'''
67 while True:
68 formula_deep = re.search("\(.[^()]+\)",formula)
69 if formula_deep:
70 formula_deep = formula_deep.group()
71 formula_list = modify(formula_deep)
72 '''得到修整好要计算的字符串,现在开始进行计算-9-2*5/-3+7/3*99/4*2998+10*568/14'''
73 calc_value = multiply_divide(formula_list)
74 formula = formula.replace(formula_deep,str(calc_value))
75 else:
76 '''处理不带括号的情形'''
77 formula = modify(formula)
78 calc_last_value = multiply_divide(formula)
79 print("formula:",calc_last_value)
80 exit()
81
82 if __name__=="__main__":
83 main(formula)
程序运行过程:
大致思路:我们知道,要计算上面字符串的格式,可以使用eval()函数,但是这里我们要自己编写一个计算器;我们知道,数学运算的优先级是括号的优先级最高,先运算括号内的东西,因此我们的思路是匹配出内存的括号,然后进行运算,当把内存括号中的内容匹配出来之后,我们计算,然后用计算出来的值替换字符串中原来位置的值,一直替换到字符串中没有括号位置,这个时候我们就按照正常的运算顺序来进行计算。
1、正则匹配,先找到内存括号;代码如下:
formula =
'1 - 2 * ( (60-30 +(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )'
formula_deep = re.search(
"\(.[^()]+\)",formula)
print( formula_deep.group())
运行结果如下:
(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )
上面我们观察提取出来内存的字符串,可以看出,有很多地方需要修饰一下,字符串中有很多空,这会影响我们计算,还有在计算的过程中我们不需要括号,因此也要去掉括号。
2、去除空格和括号;
formula_deep = re.sub( "[() ]", "", formula_deep)
运行如下:
-9-2*5/-3+7/3*99/4*2998+10*568/14
3、得到上述字符串之后,我们在逐层运算的时候,可以会出现+-,-+,++,--等情况,这个时候也要进行处理,由于现在是第一层,看不出来问题,当运算之后,如果内存得到的是负数,那么前面括号外面是+或-的话就变成+-,--等情况,这个时候也是不行的,也要进行处理;
formula_deep = re.sub(
"\+-",
'-',
formula_deep)
formula_deep = re.sub(
"-+",
'-',
formula_deep)
formula_deep = re.sub(
"\++",
"+",
formula_deep)
formula_deep = re.sub(
"--",
'+', formula_deep)
运行如下:
-9-2*5/-3+7/3*99/4*2998+10*568/14
4、当上面处理完成之后,就正式开始计算,我们知道,计算首先要计算乘除,因为乘除的优先级最高,因为要先找到乘除,计算完成之后再计算加减;
calc_sign = re.findall(
"[+-]",formula_deep)
calc_list = re.split(
"[+-]",formula_deep)
print(calc_list)
print( calc_sign)
运行如下:
['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']
['-', '-', '-', '+', '+']
我们得到了计算的列表,和运算符号, ['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14'] 里面也是有问题的,首先,列表的第一个元素是""空的情形,说明前面是-号才会有这种情况出现,这样的情况是要合并的,还有2*5/,这种说明后面跟着的也是负数,也要先进行处理才能进行预案算,为什么会出现这种情况呢?这是由于在运算的过程中,我们是以"+"或"-"来分割字符串的,这样就会造成如果是一个负数,就会被分割掉,在开头的时候,前面会被分割一个空,这样就会造成我们运算出错,因为要进行修改。
5、对上面运算进行修正:
if calc_list[
0] ==
"":
calc_list[
1] = calc_sign[
0] + calc_list[
1]
del calc_list[
0]
del calc_sign[
0]
print(
"calc_list:",calc_list)
print(
"calc_sign:",calc_sign)
for index,e
in
enumerate(calc_list):
if e.endswith(
"/")
or e.endswith(
"*"):
'''
说明后面跟着的是负数,要进行修正
'''
calc_list[index+
1] = calc_list[index] + calc_sign[index] + calc_list[index+
1]
del calc_list[index]
del calc_sign[index]
print(
"calc_list:",calc_list)
print( "calc_sign:",calc_sign)
运行如下:
calc_list: ['-9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']
calc_sign: ['-', '-', '+', '+']
calc_list: ['-9', '2*5/-3', '7/3*99/4*2998', '10*568/14']
calc_sign: ['-', '+', '+']
从上面可以看出,我们分两笔进行了修正,第一次去除了开头的""空元素问题;第二次提出了乘除后面跟着负数的情况;
6、这个时候,我们就要进行计算了,我们首先遍历 calc_list: ['-9', '2*5/-3', '7/3*99/4*2998', '10*568/14'] 中的元素,因为我们要先进行乘除,因此找到包含"/"或"*"的字符串,进行求值,然后进行替换,就可以得到没有乘除的字符串,只包含加减情况:
for num,value in enumerate(calc_list):
if "/" in value or "*" in value:
"""说明包含乘除,首先进行计算"""
mul_div_sign = re.findall("[/*]",value)
mul_div_list = re.split("[*/]",value)
print(mul_div_sign)
print(mul_div_list)
运算结果如下:
['*', '/']
['2', '5', '-3']
['/', '*', '/', '*']
['7', '3', '99', '4', '2998']
['*', '/']
['10', '568', '14']
我们得到了运算符和里面的数字,现在只要判断乘除号,然后就可以利用前面一个乘以后面一个进行计算了。如下:
7、乘除计算:
1 for num,value in enumerate(calc_list):
2 if "/" in value or "*" in value:
3 """说明包含乘除,首先进行计算"""
4 mul_div_sign = re.findall("[/*]",value)
5 mul_div_list = re.split("[*/]",value)
6 '''接下来,我们计算乘除的情况,首先我们要遍历乘除,因为要进行元素递乘'''
7 res = None
8 for e_index,e_value in enumerate(mul_div_list):
9 if res:
10 if mul_div_sign[e_index-1] == "/":
11 res /= float(e_value)
12 elif mul_div_sign[e_index-1] == "*":
13 res *= float(e_value)
14 else:
15 res = float(e_value) #如果不存在,就生成一个新的,但是我们定义的是不存在的情况,因此肯定是先生成一个数,然后在进行计算
16 calc_list[num] = res
17 else:
18 pass
19
20 print(calc_list)
21 print(calc_sign)
运行结果如下:
['-9', -3.3333333333333335, 173134.50000000003, 405.7142857142857]
['-', '+', '+']
上述代码,我们进行了乘除的运算,让运算里面不在存在乘除,只需要进行加减运算即可。
可以看见,我们运算之后,只剩下了加减,这样,我们就可以利用列表的元素和符号进行加减运算。
8、加减运算:
1 '''进行加减运算'''
2 result = None
3 for k_index,k_value in enumerate(calc_list):
4 if result:
5 if calc_sign[k_index-1] == "+":
6 result += float(k_value)
7 elif calc_sign[k_index-1] == '-':
8 result -= float(k_value)
9 else:
10 result = float(k_value)
11 print("result:",result)
运行如下:
result: 173534.54761904766
9、上面,我们得到了运算的结果,然后只需要替换内存括号的内容即可,这样一层一层替换,最终只会剩下没有括号的运算,这个时候,我们在这行这个函数,就能得到最终的结果。
知识点:
(1):
result = None
for k_index,k_value in enumerate(calc_list):
if result:
if calc_sign[k_index-1] == "+":
result += float(k_value)
elif calc_sign[k_index-1] == '-':
result -= float(k_value)
else:
result = float(k_value)
上述代码中,体现了一个思想,由于我们想实现的是前一个数字加上后一个数字,但是没有直接的方法,这个时候,我们就可以先定义一个空值,然后对这个值进行判断,其实判断的目的就是为了给这个变量赋值,赋值就是列表的第一个元素,这样我们就能实现列表中元素每次循环都进行叠加或叠减。这个思想很好。当不存在,想让它存在的时候,就先定义一个空值进行判断,判断之后在进行赋值。赋值之后,相当于result等于元素的第一个值,并且元素下一次循环也是从第二个值开始,列表的长度索引也没有超标。
2、正则表达式的利用,re(regular的缩写):
^表示非,"\"表示转义,就是让表示字符本身的含义,+代表一个或多个
"\(.[^()]+\)"代表匹配括号,括号中间是包含任意多个不是()的元素,也就是匹配最内层的括号。
3、字符串的replace()方法,就把字符串进行查找替换,str.replace(old,new),正则中字符串findall()查找元素中所有的正则表达式的值,放在一个列表中;re.split()字符串的分割,按照某个正则字符串进行分割。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 微软开源 Windows 计算器
- 基于Andriod的简易计算器
- python版亲戚关系计算器
- Python 3实现简单计算器功能
- Golang 编译原理 计算器(通俗易懂)
- 微软开源Windows计算器意外蹿红
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Designing Web Navigation
James Kalbach / O'Reilly Media / 2007-8-15 / USD 49.99
Thoroughly rewritten for today's web environment, this bestselling book offers a fresh look at a fundamental topic of web site development: navigation design. Amid all the changes to the Web in the pa......一起来看看 《Designing Web Navigation》 这本书的介绍吧!