利用正则制作计算器
核心思想: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))

浙公网安备 33010602011771号