學(xué)習(xí)python之路--Day5 計算器

需求

可以處理帶括號的加減乘除運(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)

確定以上方法之后我們先來畫流程圖


calculator

實(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)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容