用Python实现复杂的计算器,可以按照“()”、乘除、加减的优先级进行混合运算。主旨是对正则表达式进行学习。
设计思路:
1.在计算式中搜索最后一个“(”,再搜索和它匹配的“)”,截取两个括号间的表达式cul。
2.乘除的优先级高,循环搜索cul内的乘除号,进行计算后进行加减计算,得到结果ans。
3.用ans替换“(cul)”,重新搜索括号,知道将输入的公式简化成没有括号的四则运算。
4.对最后的四则运算计算结果。流程图如下:
设计时的注意事项:
1.在简化计算式过程中,如3*(1-3),简化后为3*-2,在进行乘运算的时候会报错。解决措施为将乘数前的负号移至被乘数前。将算术式更换为-3*2。除法也用相同的方法处理。
2.在出现“--”或“+-”的时候,可以把“--”替换成“+”,把“+-”替换成“-”。
代码分析:
代码的结构是这样的:
执行文件其实没啥说的!
1 import os,sys 2 BASE_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 3 print(BASE_dir) 4 sys.path.append(BASE_dir) 5 from core import main 6 if __name__ == ‘__main__‘: 7 main.run()
calculato.py就是将文件路径添加到环境变量中
1 import re 2 def mul(processor): #乘运算 3 a = re.search(r"(\d+)?[.]?(\d+)[*]", processor).group()[:-1] 4 b = re.search(r"[*]\d+[.]?(\d+)?", processor).group()[1:] 5 ans = float(a) * float(b) 6 ans = str(ans) 7 processor_past = re.sub(r"\d+[.]?(\d+)?[*]\d+[.]?(\d+)?", ans, processor, count=1) 8 return processor_past 9 def div(processor): #除运算 10 a = re.search(r"(\d+)?[.]?(\d+)[/]", processor).group()[:-1] 11 b = re.search(r"[/]\d+[.]?(\d+)?", processor).group()[1:] 12 ans = float(a) / float(b) 13 ans = str(ans) 14 processor_past = re.sub(r"\d+[.]?(\d+)?[/]\d+[.]?(\d+)?", ans, processor, count=1) 15 return processor_past 16 def add(processor): #加运算 17 a=re.search("(\d+)?[.]?(\d+)[+]",processor).group()[:-1] 18 b=re.search("[+]\d+[.]?(\d+)?",processor).group()[1:] 19 ans = float(a)+float(b) 20 ans = str(ans) 21 processor_past = re.sub(r"\d+[.]?(\d+)?[+]\d+[.]?(\d+)?",ans,processor,count=1) 22 return processor_past 23 def sub(processor): #减运算 24 a=re.search("\d+[.]?(\d+)?[-]",processor).group()[:-1] 25 b=re.search("[-]\d+[.]?(\d+)?",processor).group()[1:] 26 ans = float(a)-float(b) 27 ans = str(ans) 28 processor_past = re.sub(r"\d+[.]?(\d+)?[-]\d+[.]?(\d+)?",ans,processor,count=1) 29 return processor_past
在func.py中定义了运算的方法,由于形参是字符串形式,需将计算结果转换成字符串,然后将结果和算术式替换:如mul("3*2+1)的返回值是“6+1”。
这里还用了字符串的切片方法,删掉第一个值:[1:],删掉最后一个值为[:-1]。
以乘法为例,"*"前必须为数字,被乘数是小数的话还会有小数点和整数位,所以在正则表达式的查询关键字为r“(\d+)?[.]?(\d+)[*]”,所引出字符串后删掉最后的“*”,而“*”后紧跟的是数字,小数点和小数点后的数为非必须字符。用r"[*]\d+[.]?(\d+)?"查找。
在查询关键字时“*"和”+“为转义字符,要在字符串前加”r“
1 import re 2 from core import func 3 def find_brackets(cul): #将“()”内表达式分析出来 4 while re.search("[(].+", cul): 5 cul = re.search("[(].+", cul).group()[1:] 6 cul = cul[::-1] 7 while re.search("[)].+", cul): 8 cul = re.search("[)].+", cul).group()[1:] 9 cul = cul[::-1] 10 return (cul) 11 12 def change(search,ans,cul): #将运算结果和()里的表达式更换 13 search = re.sub("[+]", ‘\+‘,search) 14 search = re.sub("[*]", ‘\*‘,search) 15 cul = re.sub("[(]%s[)]"%search,ans,cul)#在正则表达式中插入变量 16 return cul 17 18 def change_minus(search, ans, before): # 和move_minus一起移动乘除号后面的负号 19 search = re.sub("[+]", ‘\+‘, search) 20 search = re.sub("[*]", ‘\*‘, search) 21 after = re.sub(search, ans, before) 22 return after 23 24 def move_minus(cul): 25 b = cul 26 if re.search(r"(\d+)?[.]?\d+[*][-](\d+)?[.]?\d+?", cul): 27 a = re.search(r"(\d+)?[.]?\d+[*][-](\d+)?[.]?\d+?", cul).group() 28 c = a 29 a = re.sub("[-]", "", a) 30 a = ‘-‘ + a 31 b = change_minus(c, a, cul) 32 elif re.search(r"(\d+)?[.]?\d+[/][-](\d+)?[.]?\d+?", cul): 33 a = re.search(r"(\d+)?[.]?\d+[/][-](\d+)?[.]?\d+?", cul).group() 34 c = a 35 a = re.sub("[-]", "", a) 36 a = ‘-‘ + a 37 b = change_minus(c, a, cul) 38 return b 39 40 41 def mul_div(str_past): #乘除优先级一致,进行乘除运算 42 ans = str_past 43 while re.search("[\*]|[/]",ans): 44 res = re.search("[/]|[\*]",ans).group() 45 if res == "*": 46 ans = func.mul(ans) 47 elif res =="/": 48 ans = func.div(ans) 49 return ans 50 51 def add_reduce(str_past): #加减优先级一致,进行加减运算 52 ans = str_past 53 ans = re.sub("--","+",ans) 54 ans = re.sub(r"[+][-]","-",ans) 55 while re.search(r"[+]|[-]",ans): 56 if re.match("-",ans): 57 break 58 else: 59 res = re.search(r"[+]|[-]",ans).group() 60 if res == "+": 61 ans = func.add(ans) 62 elif res =="-": 63 ans = func.sub(ans) 64 return ans 65 66 def cul(str): 67 cul = str 68 ans = str 69 while re.search("[(]",cul): 70 cul = re.sub("--", "+", cul) 71 cul = re.sub(r"[+][-]", "-", cul) 72 cul_1 = find_brackets(cul) 73 ans = mul_div(cul_1) 74 ans = add_reduce(ans) 75 ans = change(cul_1,ans,cul) 76 cul = ans 77 cul = move_minus(cul) 78 ans = move_minus(ans) 79 ans = mul_div(ans) 80 ans = add_reduce(ans) 81 return ans
calcu.py定义了整个计算的流程。
cul()中不断索引括号,将索引出的算术式计算后用结论替代。每简化一轮后检查乘除号后是否有负号的状态。
乘除法的优先级比加减高,可以把乘除的运算放在一起,
while re.search("[\*]|[/]",ans):
用这个方法可以从左到右循环搜索算术式内的乘除运算。
1 import re 2 import os,sys 3 from core import calcu,func.log 4 def run(): 5 print("欢迎使用计算器!!!") 6 while True: 7 cul = input("请输入计算公式:") 8 if cul == "exit": 9 print("退出计算器!") 10 break 11 elif re.findall("[(]", cul).__len__() != re.findall("[)]", cul).__len__(): 12 print("括号不匹配!") 13 elif re.search("[(]|[)]",cul): 14 print("请使用英文符号!") 15 elif re.search("[a-z]|[A-Z]",cul): 16 print("请输入数字!") 17 else: 18 ans = calcu.cul(cul) 19 print(ans) 20 log.logger(cul,ans)
main.py调用了整个算式的计算过程,并对输入的公式进行了一些纠错措施并在每次计算后将计算式和结论存储在日志中。
1 import time 2 def logger(cul,ans): 3 fp = open("logger.txt",‘a+‘,encoding="UTF-8") 4 now = time.time() 5 fp.write("%s %s=%s\n"%(now,cul,ans)) 6 fp.close()
log.py就是将每次运算的公式和结论存储在日志中。
存在的问题:日志文件应存储在log路径下,但是现在每次执行完会在bin路径下生成新日志文件并进行存储操作。还在想办法改进中!
原文地址:https://www.cnblogs.com/yinsedeyinse/p/10010325.html