作业:
使用正则表达式实现计算器功能。
实现:
1、实现带括号的计算
2、实现指数、加减乘除求余等功能
先看运行结果:
1 请输入您的计算式: 1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) 2 第 1 选取的()为: ★(-40.0/5)★ 3 选取 乘除 运算第 1 运算式为:★40.0/5★ 4 乘除 运算第 1 运算式的结果为: ★-8.0★ 5 第 1 选取的()计算结果为: ★-8.0★ 6 新的表达式为: 1-2*((60-30-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2)) 7 第 2 选取的()为: ★(9-2*5/3+7/3*99/4*2998+10*568/14)★ 8 选取 乘除 运算第 1 运算式为:★2*5★ 9 乘除 运算第 1 运算式的结果为: ★9-10.0/3+7/3*99/4*2998+10*568/14★ 10 选取 乘除 运算第 2 运算式为:★10.0/3★ 11 乘除 运算第 2 运算式的结果为: ★9-3.3333+7/3*99/4*2998+10*568/14★ 12 选取 乘除 运算第 3 运算式为:★7/3★ 13 乘除 运算第 3 运算式的结果为: ★9-3.3333+2.3333*99/4*2998+10*568/14★ 14 选取 乘除 运算第 4 运算式为:★2.3333*99★ 15 乘除 运算第 4 运算式的结果为: ★9-3.3333+230.9967/4*2998+10*568/14★ 16 选取 乘除 运算第 5 运算式为:★230.9967/4★ 17 乘除 运算第 5 运算式的结果为: ★9-3.3333+57.7491*2998+10*568/14★ 18 选取 乘除 运算第 6 运算式为:★57.7491*2998★ 19 乘除 运算第 6 运算式的结果为: ★9-3.3333+173131.8018+10*568/14★ 20 选取 乘除 运算第 7 运算式为:★10*568★ 21 乘除 运算第 7 运算式的结果为: ★9-3.3333+173131.8018+5680.0/14★ 22 选取 乘除 运算第 8 运算式为:★5680.0/14★ 23 乘除 运算第 8 运算式的结果为: ★9-3.3333+173131.8018+405.7142★ 24 选取 加减 运算第 1 运算式为:★9-3.3333★ 25 加减 运算第 1 运算式的结果为: ★5.6667+173131.8018+405.7142★ 26 选取 加减 运算第 2 运算式为:★5.6667+173131.8018★ 27 加减 运算第 2 运算式的结果为: ★173137.4685+405.7142★ 28 选取 加减 运算第 3 运算式为:★173137.4685+405.7142★ 29 加减 运算第 3 运算式的结果为: ★173543.1826★ 30 第 2 选取的()计算结果为: ★173543.1826★ 31 新的表达式为: 1-2*((60-30-8.0*173543.1826)-(-4*3)/(16-3*2)) 32 第 3 选取的()为: ★(60-30-8.0*173543.1826)★ 33 选取 乘除 运算第 1 运算式为:★8.0*173543.1826★ 34 乘除 运算第 1 运算式的结果为: ★60-30-1388345.4608★ 35 选取 加减 运算第 1 运算式为:★60-30★ 36 加减 运算第 1 运算式的结果为: ★30.0-1388345.4608★ 37 选取 加减 运算第 2 运算式为:★30.0-1388345.4608★ 38 加减 运算第 2 运算式的结果为: ★-1388315.4608★ 39 第 3 选取的()计算结果为: ★-1388315.4608★ 40 新的表达式为: 1-2*(-1388315.4608-(-4*3)/(16-3*2)) 41 第 4 选取的()为: ★(-4*3)★ 42 选取 乘除 运算第 1 运算式为:★4*3★ 43 乘除 运算第 1 运算式的结果为: ★-12.0★ 44 第 4 选取的()计算结果为: ★-12.0★ 45 新的表达式为: 1-2*(-1388315.4608+12.0/(16-3*2)) 46 第 5 选取的()为: ★(16-3*2)★ 47 选取 乘除 运算第 1 运算式为:★3*2★ 48 乘除 运算第 1 运算式的结果为: ★16-6.0★ 49 选取 加减 运算第 1 运算式为:★16-6.0★ 50 加减 运算第 1 运算式的结果为: ★10.0★ 51 第 5 选取的()计算结果为: ★10.0★ 52 新的表达式为: 1-2*(-1388315.4608+12.0/10.0) 53 第 6 选取的()为: ★(-1388315.4608+12.0/10.0)★ 54 选取 乘除 运算第 1 运算式为:★12.0/10.0★ 55 乘除 运算第 1 运算式的结果为: ★-1388315.4608+1.2★ 56 选取 加减 运算第 1 运算式为:★-1388315.4608+1.2★ 57 加减 运算第 1 运算式的结果为: ★-1388314.2608★ 58 第 6 选取的()计算结果为: ★-1388314.2608★ 59 新的表达式为: 1-2*-1388314.2608 60 ()选择结束,执行如上最后计算式 61 选取 乘除 运算第 1 运算式为:★2*-1388314.2608★ 62 乘除 运算第 1 运算式的结果为: ★1+2776628.5216★ 63 选取 加减 运算第 1 运算式为:★1+2776628.5216★ 64 加减 运算第 1 运算式的结果为: ★2776629.5216★ 65 最后的计算结果为: ★2776629.5216★
大致思路:
1、匹配模块:
循环匹配最内部括号,匹配后计算结果并替换原字符串
2、计算模块:
循环匹配乘除运算、匹配后计算结果并替换
循环匹配加减运算、匹配后计算结果并替换
3、里面有很多细节要注意如:
检测非法输入、保留四位小数、-号的处理原则等。
源码如下:
1 import re 2 welcome = ''' 3 ------------------------------------- 4 welcome to the counter of lmh 5 ------------------------------------- 6 ''' 7 def format_s(x): #格式化输出 8 x = re.sub(r'\s+','',x) 9 x = re.sub(r'\++|\-\-',r'+',x) 10 x = re.sub(r'\-\+|\+\-',r'-',x) 11 x = re.sub(r'\.+',r'.',x) 12 while True: 13 x1 = re.search(r'\d+\.\d{5}',x) 14 if x1 == None: 15 break 16 else: 17 x2 = re.search(r'\d+\.\d{4}',x1.group()) 18 x = re.sub(r'\d+\.\d{5,}',x2.group(),x,1) 19 return x 20 21 def islegal(x): #判断输入是否合法 22 global flag 23 flag = 0 24 ret0 = re.search('\.\d+\..*',x) 25 ret = re.sub(r'\d|\+|\-|\*|\/|\(|\)|\s+|\.+','',x) 26 if ret0 ==None and ret == '': 27 pass 28 else: 29 print('您的输入不合法请重新输入') 30 flag = 1 31 32 def cal_num(x): #二元计算式算法,x为需要处理的二元字符串 33 ss = re.search('\D',x) 34 if ss == None: 35 return x 36 else: 37 s1 = float(re.search('^\-*\d+\.?\d*',x).group()) #选取元素x 38 s2 = float(re.search('\-*\d+\.?\d*$',x).group()) #选取元素y 39 sb = re.search(r'\*',x) #匹配二元计算式是否包含元素* 40 sb2 = re.search(r'/',x) #匹配二元计算式是否包含元素/ 41 sb3 = re.search(r'\+',x) #匹配二元计算式是否包含是否元素+,前面已经格式化。有+号代表选取的二元计算式只能是+法运算 42 sb4 = re.search('\-*\d+\.?\d*\-\-*\d+\.?\d*',x) #选取元素- 注意:第一个元素可能有负号,因此需要选取左右都为数字的 43 if sb != None: 44 s4 = float(s1) * float(s2) 45 elif sb2 != None: 46 s4 = float(s1) / float(s2) 47 elif sb3 != None: 48 s4 = float(s1) + float(s2) 49 elif sb4 != None: 50 s4 = float(s1) + float(s2) 51 else: 52 s4 = float(s1) 53 s5 = str(s4) 54 return s5 55 56 def cal_select(p):#先乘除后加减方法 57 d = '乘除' 58 first = re.compile(r'\d+\.*\d*\*\-*\d+\.*\d*|\d+\.*\d*/\-*\d+\.*\d*')#匹配*号或者/前面的数字和后面的数字。注意:前面不匹配-号,后面需要匹配-号 59 second = re.compile(r'\-*\d+\.*\d*\+\-*\d+\.*\d*|\-*\d+\.*\d*\-\-*\d+\.*\d*')#匹配+号前面的数字和后面的数字。注意:前面匹配-号,后面也需要匹配-号 60 def cir(x): 61 i = 1 62 while True: 63 nonlocal p 64 s0 = x.search(p) #选取第一个2元计算式 65 if s0 == None: 66 break 67 s0 = s0.group() 68 print(' 选取 %s 运算第 %s 运算式为:★%s★'%(d,i,s0)) 69 p = re.sub(x, cal_num(s0), p,count=1) 70 p = format_s(p) 71 print(' %s 运算第 %s 运算式的结果为: ★%s★'%(d,i,p)) 72 i += 1 73 cir(first) 74 d = '加减' 75 cir(second) 76 p = format_s(p) 77 return p 78 79 while True:#判断输入合法性 80 print(welcome) 81 s = input(r'请输入您的计算式: ') 82 islegal(s) 83 if flag == 1: 84 continue 85 else: 86 break 87 s = format_s(s) 88 89 i=1 90 while True:#依次匹配最内部() 91 find_parentheses = re.compile(r'\([^()]*\)') #匹配最内部(..)方法 92 clear_parentheses = re.compile('\(|\)') #只匹配()方法 93 ret = find_parentheses.search(s) #匹配字符串s最内部括号 94 if ret == None: 95 break 96 s0 = clear_parentheses.sub('',ret.group()) #取消字符串s最内部括号,保留内部计算式s0 97 print('第 %s 选取的()为: ★%s★'%(i,ret.group())) 98 s5 = cal_select(s0) #计算s0结果 99 print('第 %s 选取的()计算结果为: ★%s★'%(i,s5)) 100 s = re.sub(find_parentheses,s5,s,count=1) #替换在s字符串中替换so 101 s = format_s(s) #刷新格式 102 print('新的表达式为: %s'%s) 103 i += 1 104 105 print('()选择结束,执行如上最后计算式') 106 s = cal_select(s) 107 print('最后的计算结果为: ★%s★'%s)