头疼,其实这个程序在我看的视频当中是当做re模块的运用来进行测试的,而到了我这里就成了简化版的了,因为我实在是做吐了,恕小弟无能,只能做简化版的。为何说是简化版呢,因为要求是给的计算式是多层嵌套的小括号“()”,然后计算的时候不能用eval方法,eval是个好东西啊,他能直接得到字符串中的结果,比如eval(“23+34*45/345-34”)=结果,是可以直接给你返回算术式的结果的,如果你自己处理这段字符串的话就要花好多工夫拆解字符串。我的简化版是将多层小括号给分为了小括号“()”、中括号“【】”、大括号“{}”,不允许使用多层相同括号连续嵌套(相应的不允许超过三层,超过三层,小弟无能为力),而我觉得,想要区分不同的层级的小括号“(()())”是需要下功夫用re正则去匹配的,而我这个用是用到正则了,但用的很少,重点全在如何自己写代码实现eval的功能了。
效果图:
另附一张各步骤计算详解
源代码:
import redef Get_FuH(As): As = As.replace('--','+') As = As.replace('+-', '+') As = As.replace('/-', '/') As = As.replace('*-', '*') End = [] As = list(As) if (As[1] == '-'): As.pop(1) for i in As: if(i == '/' or i == '+' or i == '*' ): End.append(i) elif(i == '-'): End.append('+') for i in End: if(i == ''): End.pop(End.index('')) return Enddef Get_Num(As): As = As.replace('--', '-') As = As.replace('+-', '-') As = As.replace('/-', '-') As = As.replace('*-', '-') As = list(As) Get = [] End = [] for i in As: if(i <= "9" and i >= "0" or i == '.'): Get.append(i) else: End.append(''.join(Get)) Get = [] if(i == '-'):Get.append(i) for i in End: if(i == ''): End.pop(End.index('')) for i in End: if(i == ''): End.pop(End.index(i)) return Enddef Do_Xiao(As): a = re.findall("\([+\-*/0-9.]*\)",As) # print(a) for i in a: TiH = i ShuZ = Get_Num(TiH) FuH = Get_FuH(TiH) ShuZ_New = [] FuH_New = [] # print(TiH) # print(ShuZ) # print(FuH) for q in FuH: if (q == '*'): m = FuH.index('*') End = float(ShuZ[m]) * float(ShuZ[m + 1]) ShuZ[m] = 0 FuH[m] = 0 ShuZ[m+1] = End elif (q == '/'): m = FuH.index('/') End = float(ShuZ[m]) / float(ShuZ[m + 1]) ShuZ[m] = 0 FuH[m] = 0 ShuZ[m + 1] = End for i in ShuZ: if (i != 0): ShuZ_New.append(i) for i in FuH: if (i != 0): FuH_New.append(i) # print(ShuZ_New) # print(FuH_New) for i in FuH_New: if (i == '+'): n = FuH_New.index('+') End = float(ShuZ_New[n]) + float(ShuZ_New[n + 1]) ShuZ_New[n] = 0 FuH_New[n] = 0 ShuZ_New[n + 1] = float(End) elif (i == '-'): n = FuH_New.index('-') End = float(ShuZ_New[n]) - float(ShuZ_New[n + 1]) ShuZ_New[n] = 0 FuH_New[n] = 0 ShuZ_New[n + 1] = float(End) for p in ShuZ_New: if (p != 0): As = As.replace(TiH, str(p)) return Asdef Do_Zhong(As): As = As.replace("[","(") As = As.replace("]",")") As = Do_Xiao(As) return Asdef Do_Da(As): As = As.replace("{","(") As = As.replace("}",")") # print(As) As = Do_Xiao(As) return Asdef End_end(As): As = '(' + As + ')' End = Do_Xiao(As) return Endif __name__ == '__main__': AA = "1-2*{[60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14)]-(-4*3)/(16-3*2)}" BB = "34+45*{44+34*45+44/45}-{[34*45/44]*(456+466*345-3445/455)}" As = input("请输入你要计算的式子:") As = Do_Xiao(As) print(As) As = Do_Zhong(As) print(As) As = Do_Da(As) print(As) End = End_end(As) print(End)解析:我的整体思路很简单,就是按顺序一步步提取,先用正则把小括号的内容提取出来,因为有格式要求,所以提取的小括号的内容都是闭合的(即()中间不会出现()或者单边括号,匹配较为容易)。对提取的内容进行处理:定义了几个函数:1、提取数字,我将提取的字符串转为列表,然后把通过运算符分割的数字(之所以取运算符是因为有多位数还有小数点的存在,这样可以将一个数字完整的存放在一起)按个存放到一个列表中。2、提取运算符,直接扫描字符串列表提取即可。3、运算,因为运算符是两个数进行运算,所以通过循环运算符,每一个运算符都是运算符左右两个数的和。为了区分优先级(先乘除后加减),我进行了两边循环符号,且第二遍循环是在第一次的基础上删除了乘除运算符后的列表。即第一遍循环只算乘除,第二遍再算加减。4、中括号转小括号,一定要在小括号运算完,公式中没有小括号才能调用。5、大括号转小括号,同理中括号,因为如果大括号转成小括号,里面还有中括号会卡在中括号上没有匹配符。再说说中间的遇到的一些bug,也是导致代码混乱的地方,这些我都没来的及优化,测视了两个算术式没问题就不搞了,头疼。1、提取数字,“-”是个大问题,到底把他算在运算符列表中呢还是算在数字列表中呢,我选择的是放在数字中,即数字分正负,由此我需要判断“+-”、“--”、“/-”、“*-”,后两个还好说,前两个真是搞死了,就在那算负负、正正的逻辑去了,还要在表达式中进行替换工作,将双符号进行缩减成标准的单符号传进符号列表中,因为符号列表的数目一旦不对,就会导致数字列表没有匹配正确(这也是最麻烦的地方,中间出了好几次超出列表范围的bug)。另一个问题比较严重的问题是在乘除算完给加减新的列表的时候,因为有连乘连除的存在,所以我需要将计算的结果再存到列比中循环利用,我的方法是算一个弹出一个,既可以继续运行,还可以缩减列表,到最后符号列表为空,数字列表还剩一个结果。呵呵,理想很丰满,结果最大的bug出来了,找了好半天,把所有的循环都输出了一遍才找到原因:因为我是用for循环,通过i in 符号列表,然后当i匹配到运算符,就找到这个下表,然后弹出去这个运算符元素,数字列表弹出去两个数字,但当我符号弹出去这个后,列表索引自动迁移,导致i+1成了i,i+1还没进行循环,就变成了下一次循环到了i+2,简单说就是每一次循环i+1,当我弹出当前位置i后,i(y) = i+1,且这是在本次循环结束前,所以当下一次循环开始时,其实是y+1,也就是上一次循环中的i(i已经被弹出去了,i成了i+1)的后面的后面这个元素,及跳过了一个i的循环,为了避免这种情况,我不弹出元素,而是全都初始化为0,当乘除运算完后,再进行“除0”,即构造新列表再次进行加减运算。使用说明:大、中、小括号必须数目,位置等对称,且不能乱套,中规中举的小中大或者小中、小大、中大,不可小套大。式子中用到那种括号就调用一次对应的函数,且从小往大一层层的调。我没有设检查式子是否合规,讲道理应该不会再出什么问题了,AA的式子是我照着这个写的程序,BB是用来测试的,我只测试了这一个,毕竟长公式写起来也麻烦,自己再在手机上算一遍也麻烦,但AA、BB的式子我都在手机上算过了,都对,且更精确。