需求
可以處理帶括號的加減乘除運(yùn)算
需求分析
匹配括號
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)
確定以上方法之后我們先來畫流程圖

實(shí)現(xiàn)
可以看到我們的邏輯是用re.findall(r'\([^()]+\)')判斷是否存在括號,如果存在,我們就進(jìn)入處理([^()]+)最里面括號的內(nèi)容
這是一個循環(huán),直到處理的沒有([^()]+)這一項(xiàng),也就代表沒有括號內(nèi)的內(nèi)容了
如果一開始就沒有匹配到([^()]+),那我們就直接按加減乘除的規(guī)則處理他
一開始的循環(huán)可以這么寫:
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)
然后按著流程圖,先處理高級運(yùn)算符,也就是乘法和除法運(yùn)算符,我們先處理除法,這是因?yàn)樵趯?shí)際操作中,除法必須按從左到右的順序運(yùn)算,除法運(yùn)算符先算左邊的和先算右邊的結(jié)果,是天差地別的變化,乘法還好,先乘左邊的還是先乘右邊的結(jié)果都是一樣,請看下面的列子:
>>> 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)
如果我們發(fā)現(xiàn)運(yùn)算行里有'/'這個符號,代表除法,那么我們就把運(yùn)算行第一個除法公式提取出來,用division_cal=re.search('[0-9]+.[0-9]+/[\+\-]?[0-9]+.[0-9]+',operation).group(),匹配出來的是[0-9]+.[0-9]+/[+-]?[0-9]+.[0-9]+,就是兩個有小數(shù)點(diǎn)的數(shù)字中間是 / 除法運(yùn)算符,例如34.5/-55.6這種。
然后把除法運(yùn)算符左邊的數(shù)字拿出來num1=re.findall('([0-9]+.[0-9]+)/',operation),是一個列表,會把所有'/'左邊的數(shù)字拿出來
再把除法運(yùn)算符右邊的數(shù)字拿出來num2=re.findall('/([\+\-]?[0-9]+.[0-9]+)',operation),同理也是一個列表
num1=float(num1[0]) num2=float(num2[0])
我們算兩個列表里第一位的數(shù)字,因?yàn)閮蓚€列表里項(xiàng)目是一一匹配的(如果輸入的運(yùn)算式正確的話),兩個列表的第一位就代表他們是這個運(yùn)算行第一個除法運(yùn)算
算出的結(jié)果,用這個結(jié)果替換第一個除法公式 operation=operation.replace(division_cal,str(division_result))
這個運(yùn)算行就少了一個除法公式
再循環(huán),直到?jīng)]有任何除法公式
接著,我們把沒有除法公式了的運(yùn)算行輸入乘法函數(shù)里處理。目的是把所有乘法公式也替換掉
邏輯如下:
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)
跟除法的規(guī)則一樣,先找到第一個乘法公式,然后提取乘法符號'*'左邊和右邊的數(shù)字,相乘出結(jié)果,替換公式,再循環(huán),直到?jīng)]有任何乘法
如果乘法和除法的處理都做完了,那接下去可以想象,就只剩下加減了
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)
之前的運(yùn)算可能還留下括號沒有處理,我們用new_operation=operation.strip('()')這一句來去掉左右括號
if len(re.split('[+-]',new_operation)) > 1
這是判斷除了'+-'號之外,還有幾項(xiàng)數(shù)字,如果大于1,那就是還需要運(yùn)算,當(dāng)然這樣就有個漏洞,如果是'-34.5'這種數(shù)字,re.split('[+-]','-34.5')這種方法分裂出來的項(xiàng)目是[],[34.5] 這樣也是大于1項(xiàng)的,所以我們加一句
if re.split('[+-]',new_operation)[0]:
來判斷分裂出來的第一位是不是空
接下來,pri_cal=re.search('[\+\-]?[0-9]+.[0-9]+[\+\-][0-9]+.[0-9]+',new_operation).group() 提取出第一個加減運(yùn)算公式
num1=re.findall('([\+\-]?[0-9]+.[0-9]+)[\+\-]',pri_cal) 提取左邊的數(shù)字
num2=re.findall('[\+\-]?[0-9]+.[0-9]+([\+\-][0-9]+.[0-9]+)',pri_cal 提取右邊的數(shù)字
運(yùn)算,因?yàn)槲覀兤ヅ溆疫厰?shù)字的時候已經(jīng)把加減號也匹配進(jìn)去了,python是支持1+-1這樣運(yùn)算的,所以我們運(yùn)算直接就是把兩個值加一起
operation=operation.replace(pri_cal,str(pri_result)) 拿運(yùn)算結(jié)果替換加減運(yùn)算式
循環(huán)
這里可能會遇到這么幾種情況,一個是,經(jīng)過一輪處理之后 34-(-5*11) 這種變成了34--55這種公式,到我們加減處理的邏輯里就無法匹配了,還有34+-55,34--55這種情況出現(xiàn),[+-]?[0-9]+.[0-9]+([+-][0-9]+.[0-9]+匹配里也沒有,當(dāng)然我們也可以中間的[+-]寫成[+-]{1,2}這種匹配一到兩次的,但是接下去的運(yùn)算可不能成功算出34+--55的結(jié)果,所以單獨(dú)做個函數(shù)把這些不合法的運(yùn)算符處理下
def symbol_judge(enter):
if '+-' in enter:
enter=enter.replace('+-','-')
elif '-+' in enter:
enter=enter.replace('-+','-')
elif '--' in enter:
enter=enter.replace('--','+')
return enter
完善一下之前的循環(huán)
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)
先處理括號內(nèi)的內(nèi)容,按照先乘除,再加減,結(jié)果去除左右括號,替換運(yùn)算行里的(^[]+)內(nèi)容,最后再對運(yùn)算行里的不合法符號做個判斷,傳給開始的循環(huán),再走一輪
終于我們的運(yùn)算式里沒有了括號,接著就該直接按先乘除后加減的四則運(yùn)算邏輯,處理它們了
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
這里面有個小細(xì)節(jié),如果運(yùn)算式開頭是-34/55+66...這樣子的,咱們之前寫的邏輯就要再改了,好多地方也要調(diào)整,為了方便復(fù)用之前的代碼,也是偷懶,其實(shí)只用在'-'號前面加一個0即可,邏輯走得通,同時不影響結(jié)果
好了,完整的代碼如下:
#-*- coding:utf-8 -*-
#owner:houyizhong
import re
print('輸入數(shù)字必須保留小數(shù)點(diǎn)一位\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)