计算器开发
- 实现加减乘除及拓号优先级解析
- 用户输入 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 def check_expression(string): 4 check_result = True 5 #括号是否匹配 6 if not string.count("(") == string.count(")"): 7 print("表达式错误,括号未闭合!") 8 check_result = False 9 if re.findall('[a-z]',string.lower()): 10 print("表达式错误,包含非法字符!") 11 check_result = False 12 13 return check_result 14 15 #格式化字符串 16 def format_string(string): 17 string = string.replace("--","+") 18 string = string.replace("-+","-") 19 string = string.replace("++","+") 20 string = string.replace("+-","-") 21 string = string.replace("*+","*") 22 string = string.replace("/+","/") 23 string = string.replace(' ','') 24 return string 25 26 #计算乘,除法#(30+6*2) 27 def calc_mul_div(string): 28 #从字符串中获取一个乘法的表达式 29 # regular = "d+.{0,}d{0,}[*/][-]{0,}d+.{0,}d{0,}" 30 regular = "d+.?d*([*/]|**)[-]?d+.?d*" 31 #如果还能找到乘或除法表达式 32 while re.findall(regular,string): 33 #获取表达式 34 expression = re.search(regular,string).group() 35 36 #如果是乘法 37 if expression.count("*")==1: 38 #获取要计算的两个数 39 x,y = expression.split("*") 40 #计算结果 41 mul_result = str(float(x) * float(y)) 42 #将计算的表达式替换为计算结果值 43 string = string.replace(expression,mul_result) 44 #格式化一下 45 string = format_string(string) 46 47 #如果是除法 48 if expression.count("/"): 49 #获取要计算的两个数 50 x,y = expression.split("/") 51 #计算除法 52 div_result = str(float(x) / float(y)) 53 #用结果替换表达式 54 string = string.replace(expression,div_result) 55 string = format_string(string) 56 57 if expression.count('*')==2: 58 x,y = expression.split('**') 59 pow_result = 1 60 for i in range(int(y)): 61 pow_result*=int(x) 62 string = string.replace(expression,str(pow_result)) 63 string = format_string(string) 64 return string 65 66 #计算加,减法 67 def calc_add_sub(string):##(30+12-23+24-3) 68 #(30+12-23+24-3) 69 #定义正则表达式 70 #add_regular = "[-]{0,}d+.{0,}d{0,}+[-]{0,}d+.{0,}d{0,}" 71 #sub_regular = "[-]{0,}d+.{0,}d{0,}-[-]{0,}d+.{0,}d{0,}" 72 add_regular = '[-]?d+.?d*+[-]?d+.?d*' 73 sub_regular = '[-]?d+.?d*-[-]?d+.?d*' 74 75 #开始加法 76 while re.findall(add_regular,string): 77 #把所有的加法都算完,获取所有加法表达式 78 add_list = re.findall(add_regular,string) 79 for add_str in add_list: 80 #获取两个加法的数 81 x,y = add_str.split("+") 82 add_result = "+" + str(float(x) + float(y)) 83 string = string.replace(add_str,add_result) 84 string = format_string(string) 85 86 #开始减法 87 while re.findall(sub_regular,string): 88 sub_list = re.findall(sub_regular,string) 89 for sub_str in sub_list: 90 numbers = sub_str.split("-") 91 #-3-5的情况split会返回3个值 92 if len(numbers) == 3: 93 result = 0 94 for v in numbers: 95 if v: 96 result -= float(v) 97 else: 98 x,y = numbers 99 result = float(x) - float(y) 100 #替换字符串 101 string = string.replace(sub_str,"+" + str(result)) 102 string = format_string(string) 103 return string 104 105 106 107 108 if __name__ == "__main__": 109 source = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )' 110 #source = "2-((-40/5)*(4-3))" 111 #source = "3**2" 112 #source = "3*6*8" 113 114 if check_expression(source): 115 print("source:",source) 116 print("eval result",eval(source)) 117 source = format_string(source) 118 print(source) 119 120 while source.count("(") > 0: 121 #格式化 122 #去括号,得到括号的字符串,结果如:(30+6/3) 123 strs = re.search('([^()]*)',source).group() 124 #将括号的表达式进行乘,除运算 125 replace_str = calc_mul_div(strs) 126 #将运算的结果在进行加,减运算 127 replace_str = calc_add_sub(replace_str) 128 #将括号的字符串替换为计算结果,结果包含(),替换时去掉():[1:-1] 129 source = format_string(source.replace(strs,replace_str[1:-1])) 130 131 else: 132 #没有括号就到最后单一表达式了 133 # 算乘除 134 replace_str = calc_mul_div(source) 135 #算加减 136 replace_str = calc_add_sub(replace_str) 137 source = source.replace(source,replace_str) 138 print("my result:",source.replace("+",""))
1 source: 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) 2 eval result 2776672.6952380957 3 1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2)) 4 my result: 2776672.6952380957 5 6 Process finished with exit code 0