需求
可以处理带括号的加减乘除运算
需求分析
匹配括号
re.search('\(.*\)',a)
匹配最里面括号
re.search(r'\([^()]+\)')
可以用strip()
方法去掉括号
计算公式
1.0-2.0((60.0-30.0+(-40.0/5.0)(9.0-2.05.0/3.0+7.0/3.099.0/4.02998.0+10.0568.0/14.0)))
匹配二级括号
re.search('\(\(.*\)\)',a)
确定以上方法之后我们先来画流程图
实现
可以看到我们的逻辑是用re.findall(r'\([^()]+\)')
判断是否存在括号,如果存在,我们就进入处理([^()]+)最里面括号的内容
这是一个循环,直到处理的没有([^()]+)这一项,也就代表没有括号内的内容了
如果一开始就没有匹配到([^()]+),那我们就直接按加减乘除的规则处理他
一开始的循环可以这么写:
loop_flag2=True
while loop_flag2:
if re.findall('\([^()]+\)',enter):
enter=three_level_brackets_func(enter)
else:
loop_flag2=False
else:
finnal_result=no_brackets_func(enter)
print(finnal_result)
然后按着流程图,先处理高级运算符,也就是乘法和除法运算符,我们先处理除法,这是因为在实际操作中,除法必须按从左到右的顺序运算,除法运算符先算左边的和先算右边的结果,是天差地别的变化,乘法还好,先乘左边的还是先乘右边的结果都是一样,请看下面的列子:
>>> 3/4/5
0.15
>>> 3/(4/5)
3.75
#乘法
>>> 3*4*5
60
>>> 3*(4*5)
60
除法这部分的逻辑如下:
while True:
if operation.find('/') != -1:
division_cal=re.search('[0-9]+.[0-9]+/[\+\-]?[0-9]+.[0-9]+',operation).group()
num1=re.findall('([0-9]+.[0-9]+)/',operation)
num2=re.findall('/([\+\-]?[0-9]+.[0-9]+)',operation)
print('division left:',num1)
print('division right:',num2)
num1=float(num1[0])
num2=float(num2[0])
division_result=num1/num2
print('division result:',division_result)
operation=operation.replace(division_cal,str(division_result))
print('now operation is:',operation)
如果我们发现运算行里有'/'这个符号,代表除法,那么我们就把运算行第一个除法公式提取出来,用division_cal=re.search('[0-9]+.[0-9]+/[\+\-]?[0-9]+.[0-9]+',operation).group()
,匹配出来的是[0-9]+.[0-9]+/[+-]?[0-9]+.[0-9]+,就是两个有小数点的数字中间是 / 除法运算符,例如34.5/-55.6这种。
然后把除法运算符左边的数字拿出来num1=re.findall('([0-9]+.[0-9]+)/',operation)
,是一个列表,会把所有'/'左边的数字拿出来
再把除法运算符右边的数字拿出来num2=re.findall('/([\+\-]?[0-9]+.[0-9]+)',operation)
,同理也是一个列表
num1=float(num1[0]) num2=float(num2[0])
我们算两个列表里第一位的数字,因为两个列表里项目是一一匹配的(如果输入的运算式正确的话),两个列表的第一位就代表他们是这个运算行第一个除法运算
算出的结果,用这个结果替换第一个除法公式 operation=operation.replace(division_cal,str(division_result))
这个运算行就少了一个除法公式
再循环,直到没有任何除法公式
接着,我们把没有除法公式了的运算行输入乘法函数里处理。目的是把所有乘法公式也替换掉
逻辑如下:
elif operation.find('*') != -1:
mutlip_cal=re.search('[0-9]+.[0-9]+\*[\+\-]?[0-9]+.[0-9]+',operation).group()
num1=re.findall('([0-9]+.[0-9]+)\*',operation)
num2=re.findall('\*([\+\-]?[0-9]+.[0-9]+)',operation)
print('multiplication left:',num1)
print('multiplication right:',num2)
num1=float(num1[0])
num2=float(num2[0])
mutlip_result=num1*num2
print('multiplication result:',mutlip_result)
operation=operation.replace(mutlip_cal,str(mutlip_result))
print('now operation is:',operation)
跟除法的规则一样,先找到第一个乘法公式,然后提取乘法符号'*'左边和右边的数字,相乘出结果,替换公式,再循环,直到没有任何乘法
如果乘法和除法的处理都做完了,那接下去可以想象,就只剩下加减了
while loop_flag:
new_operation=operation.strip('()')
if len(re.split('[+-]',new_operation)) > 1 and re.split('[+-]',new_operation)[0]:
pri_cal=re.search('[\+\-]?[0-9]+.[0-9]+[\+\-][0-9]+.[0-9]+',new_operation).group()
num1=re.findall('([\+\-]?[0-9]+.[0-9]+)[\+\-]',pri_cal)
num2=re.findall('[\+\-]?[0-9]+.[0-9]+([\+\-][0-9]+.[0-9]+)',pri_cal)
num1=float(num1[0])
num2=float(num2[0])
pri_result=num1+num2
operation=operation.replace(pri_cal,str(pri_result))
print('now operation is:',operation)
之前的运算可能还留下括号没有处理,我们用new_operation=operation.strip('()')
这一句来去掉左右括号
if len(re.split('[+-]',new_operation)) > 1
这是判断除了'+-'号之外,还有几项数字,如果大于1,那就是还需要运算,当然这样就有个漏洞,如果是'-34.5'这种数字,re.split('[+-]','-34.5')
这种方法分裂出来的项目是[],[34.5] 这样也是大于1项的,所以我们加一句
if re.split('[+-]',new_operation)[0]:
来判断分裂出来的第一位是不是空
接下来,pri_cal=re.search('[\+\-]?[0-9]+.[0-9]+[\+\-][0-9]+.[0-9]+',new_operation).group()
提取出第一个加减运算公式
num1=re.findall('([\+\-]?[0-9]+.[0-9]+)[\+\-]',pri_cal)
提取左边的数字
num2=re.findall('[\+\-]?[0-9]+.[0-9]+([\+\-][0-9]+.[0-9]+)',pri_cal
提取右边的数字
运算,因为我们匹配右边数字的时候已经把加减号也匹配进去了,python是支持1+-1这样运算的,所以我们运算直接就是把两个值加一起
operation=operation.replace(pri_cal,str(pri_result))
拿运算结果替换加减运算式
循环
这里可能会遇到这么几种情况,一个是,经过一轮处理之后 34-(-5*11) 这种变成了34--55这种公式,到我们加减处理的逻辑里就无法匹配了,还有34+-55,34--55这种情况出现,[+-]?[0-9]+.[0-9]+([+-][0-9]+.[0-9]+匹配里也没有,当然我们也可以中间的[+-]写成[+-]{1,2}这种匹配一到两次的,但是接下去的运算可不能成功算出34+--55的结果,所以单独做个函数把这些不合法的运算符处理下
def symbol_judge(enter):
if '+-' in enter:
enter=enter.replace('+-','-')
elif '-+' in enter:
enter=enter.replace('-+','-')
elif '--' in enter:
enter=enter.replace('--','+')
return enter
完善一下之前的循环
def process(enter,re_result):
for i in re_result:
pre_symbol_result=pre_symbol_cal(i)
pri_symbol_result=pri_symbol_cal(pre_symbol_result)
pri_symbol_result=pri_symbol_result.strip('()')
enter=enter.replace(i,pri_symbol_result)
return enter
def three_level_brackets_func(enter):
re_result=re.findall(r'\([^()]+\)',enter)
print('brackets inner:',re_result)
enter=process(enter,re_result)
enter=symbol_judge(enter)
print(enter)
return enter
loop_flag2=True
while loop_flag2:
if re.findall('\([^()]+\)',enter):
enter=three_level_brackets_func(enter)
else:
loop_flag2=False
else:
finnal_result=no_brackets_func(enter)
print(finnal_result)
先处理括号内的内容,按照先乘除,再加减,结果去除左右括号,替换运算行里的(^[]+)内容,最后再对运算行里的不合法符号做个判断,传给开始的循环,再走一轮
终于我们的运算式里没有了括号,接着就该直接按先乘除后加减的四则运算逻辑,处理它们了
def no_brackets_func(enter):
print('HIT no_brackets')
if enter[0] == '-':
enter='0'+enter
raw_enter=pre_symbol_cal(enter)
raw_enter=symbol_judge(raw_enter)
enter=pri_symbol_cal(raw_enter)
print(enter)
return enter
这里面有个小细节,如果运算式开头是-34/55+66...这样子的,咱们之前写的逻辑就要再改了,好多地方也要调整,为了方便复用之前的代码,也是偷懒,其实只用在'-'号前面加一个0即可,逻辑走得通,同时不影响结果
好了,完整的代码如下:
#-*- coding:utf-8 -*-
#owner:houyizhong
import re
print('输入数字必须保留小数点一位\n例子:1.0-2.0*((60.0-30.0+(-40.0/5.0)*(9.0-2.0*5.0/3.0+7.0/3.0*99.0/4.0*2998.0+10.0*568.0/14.0))+(65.0+77.0)+6.0)')
enter=input('>>>')
def pre_symbol_cal(operation):
loop_flag=True
while loop_flag:
if operation.find('/') != -1:
division_cal=re.search('[0-9]+.[0-9]+/[\+\-]?[0-9]+.[0-9]+',operation).group()
num1=re.findall('([0-9]+.[0-9]+)/',operation)
num2=re.findall('/([\+\-]?[0-9]+.[0-9]+)',operation)
print('division left:',num1)
print('division right:',num2)
num1=float(num1[0])
num2=float(num2[0])
division_result=num1/num2
print('division result:',division_result)
operation=operation.replace(division_cal,str(division_result))
print('now operation is:',operation)
elif operation.find('*') != -1:
mutlip_cal=re.search('[0-9]+.[0-9]+\*[\+\-]?[0-9]+.[0-9]+',operation).group()
num1=re.findall('([0-9]+.[0-9]+)\*',operation)
num2=re.findall('\*([\+\-]?[0-9]+.[0-9]+)',operation)
print('multiplication left:',num1)
print('multiplication right:',num2)
num1=float(num1[0])
num2=float(num2[0])
mutlip_result=num1*num2
print('multiplication result:',mutlip_result)
operation=operation.replace(mutlip_cal,str(mutlip_result))
print('now operation is:',operation)
else:
loop_flag=False
return operation
def pri_symbol_cal(operation):
loop_flag=True
while loop_flag:
new_operation=operation.strip('()')
if len(re.split('[+-]',new_operation)) > 1 and re.split('[+-]',new_operation)[0]:
pri_cal=re.search('[\+\-]?[0-9]+.[0-9]+[\+\-][0-9]+.[0-9]+',new_operation).group()
num1=re.findall('([\+\-]?[0-9]+.[0-9]+)[\+\-]',pri_cal)
num2=re.findall('[\+\-]?[0-9]+.[0-9]+([\+\-][0-9]+.[0-9]+)',pri_cal)
num1=float(num1[0])
num2=float(num2[0])
pri_result=num1+num2
operation=operation.replace(pri_cal,str(pri_result))
print('now operation is:',operation)
else:
loop_flag=False
return operation
def symbol_judge(enter):
if '+-' in enter:
enter=enter.replace('+-','-')
elif '-+' in enter:
enter=enter.replace('-+','-')
elif '--' in enter:
enter=enter.replace('--','+')
return enter
def process(enter,re_result):
for i in re_result:
pre_symbol_result=pre_symbol_cal(i)
pri_symbol_result=pri_symbol_cal(pre_symbol_result)
pri_symbol_result=pri_symbol_result.strip('()')
enter=enter.replace(i,pri_symbol_result)
return enter
def three_level_brackets_func(enter):
re_result=re.findall(r'\([^()]+\)',enter)
print('brackets inner:',re_result)
enter=process(enter,re_result)
enter=symbol_judge(enter)
print(enter)
return enter
def no_brackets_func(enter):
print('HIT no_brackets')
if enter[0] == '-':
enter='0'+enter
raw_enter=pre_symbol_cal(enter)
raw_enter=symbol_judge(raw_enter)
enter=pri_symbol_cal(raw_enter)
print(enter)
return enter
loop_flag2=True
while loop_flag2:
if re.findall('\([^()]+\)',enter):
enter=three_level_brackets_func(enter)
else:
loop_flag2=False
else:
finnal_result=no_brackets_func(enter)
print(finnal_result)