利用正则制作计算器
核心思想:1.先考虑没有括号的式子如何进行运算,然后考虑正则匹配有括号的式子,通过逐步替换
利用正则计算:1 - 2 * ( (60-30 +(-40/5) * 20) - (-4*3)/ (16-3*2) )
# 方案1
#!/usr/bin/env python # -*- coding:utf-8 -*- # author: Learning time:2018/4/30 import re # 定义一个乘除运算函数,最终返回一个运算结果 def mul_div(cal): if '*' in cal: x, y = cal.split('*') return float(x) * float(y) if '/' in cal: x, y = cal.split('/') return float(x) / float(y) # 定义一个处理加减符号的函数,这步是由于乘除运算完可能为负导致的 def proce_symbol(cal): cal = cal.replace('++','+') cal = cal.replace('+-', '-') cal = cal.replace('--', '+') cal = cal.replace('-+', '-') return cal # 定义一个对内层没有括号的公式进行运算的函数,最终返回一个结果 def inner(content): """ 这步对内层的乘除进行循环处理,直到里面没有了乘除运算,全部替换成了结果 :param content: :type content: :return: 一个不带括号的运算式的结果 :rtype: """ # 浮点型匹配整数和浮点数啊哥,不是整数匹配浮点数 # 最后变成这样1-2*-128.8,要注意这里的正则匹配 con = re.search(r'\d+\.?\d*[*/]\-?\d+\.?\d*', content) while con: # 如果当中有乘除号 con = con.group() temp = mul_div(con) # 得到结果 content = content.replace(con,str(temp)) # 对内层运算式进行替换 content = proce_symbol(content) #替换计算式中的乘除运算,直到替换完,对于冲突的+-号也进行替换 return inner(content) # 通过循环一直运算式中的乘除运算计算完 else: # 如果没有乘除号 # 对加减进行运算处理,把他们整到列表里面,挨个进行处理计算 lis = re.findall(r'[+-]?\d+\.?\d*', content) if len(lis)>0: total_num = 0 for i in lis: total_num += float(i) return total_num else: return lis[0] # 匹配最内层的括号 def pars(cal): """ 定义一个计算最内层运算的函数 :param cal: :type cal: :return:最能层运算 :rtype: """ par = re.search('\(([^()]*)\)', cal) while par: # 如果当中有括号 content = par.group() # (-40/5) temp = inner(content.strip('()')) # 去括号,并处理结果-8 cal = cal.replace(content,str(temp)) return pars(cal) # 判断里面的运算符,可以有加减乘除 else: ret = inner(cal) # 如果没有括号 return ret a = input('计算式:').strip() # 去除空格处理,得到1-2*((60-30+(-40/5)*20)-(-4*3)/(16-3*2)) a = re.sub('\s','', a) print(pars(a))
方案2:
import re def cal(exp): if '*' in exp: a,b = exp.split('*') return str(float(a) * float(b)) elif '/' in exp: a, b = exp.split('/') return str(float(a) / float(b)) def format(exp): exp = exp.replace('++',"+") exp = exp.replace('-+',"-") exp = exp.replace('+-',"-") exp = exp.replace('--',"+") return exp def dealwith(no_bracket_exp): # 匹配乘除法 while True: mul_div = re.search('\d+(\.?\d+)?[*/]-?\d+(\.?\d+)?', no_bracket_exp) if mul_div: exp = mul_div.group() result = cal(exp) no_bracket_exp = no_bracket_exp.replace(exp, result, 1) # (-8) else:break no_bracket_exp = format(no_bracket_exp) # 计算加减法 lst = re.findall(r'[-+]?\d+(?:\.\d+)?', no_bracket_exp) res = str(sum([float(i) for i in lst])) return res # 返回一个计算完毕的字符串数据类型的 数字 def remove_bracket(s): s = s.replace(' ', '') # 去掉空格 while True: ret = re.search(r'\([^()]+\)', s) # 匹配最内层的括号 if ret: # 能匹配到括号 就先处理括号内的加减乘除 no_bracket_exp = ret.group() # 拿到括号中的表达式 ret = dealwith(no_bracket_exp) # 把括号中的表达式交给的dealwith s = s.replace(no_bracket_exp, ret, 1) else: # 不能匹配到括号 就字节处理加减乘除 ret = dealwith(s) # 把表达式交给的dealwith return ret s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )' print(remove_bracket(s))
和方案二一样:
a = '1 - 2 * ( (60-30 +(-40/5) * 20) - (-4*3)/ (16-3*2) )' import re new_a = re.sub(' ','',a) # 去括号处理 def proce_symbol(cal): # 去重复加减号 if '++' in cal:cal = cal.replace('++','+') if '+-' in cal:cal = cal.replace('+-', '-') if '--' in cal:cal = cal.replace('--', '+') if '-+' in cal:cal = cal.replace('-+', '-') return cal def mul_div(famula): if '*' in famula: num1, num2 = famula.split('*') total = str(float(num1) * float(num2)) return total if '/' in famula: num1, num2 = famula.split('/') total = str(float(num1) / float(num2)) return total def total(famula): while True: if '*' or '/' in famula: num = re.search(r'\d+(\.?\d+)?[*/]\-?\d+(\.?\d+)?',famula) if num: num = num.group() nums = mul_div(num) famula = famula.replace(num, nums, 1) famula = proce_symbol(famula) # 如果算式中剩下加减运算 else: lis = re.findall(r'[-]?\d+(?:\.?\d+)?',famula) sums = sum([float(i) for i in lis]) return sums def bras(famu): while True: bra = re.search('\([^()]+\)',famu) # 获取括号内的内容 if bra: bra = bra.group() ret = total(bra) famu = famu.replace(bra,str(ret),1) s = proce_symbol(famu) return bras(s) else: s = proce_symbol(famu) ret = total(s) return ret print(bras(new_a))