作業:計算器開發 (1)實現加減乘除及拓號優先順序解析; (2)用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式後,必須自己解析裡面的(),+,- ...
作業:計算器開發
(1)實現加減乘除及拓號優先順序解析;
(2)用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式後,必須自己解析裡面的(),+,-,*,/符號和公式,運算後得出結果,結果必須與真實的計算器所得出的結果一致。
思路:
(1)首先我們要找到記憶體括弧中的內容,使用正則表達式,在這裡,記憶體括弧中我們選取比較複雜的(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 );
(2)找到記憶體括弧中的內容之後,我們只要對內層括弧中的內容就行計算,接下來只要重覆找記憶體括弧即可;
(3)首先把找到的記憶體字元串括弧去掉-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14;
(4)然後我們在進行修正,把字元串中的空格去掉,把“+-”轉化為“-”,把“--”轉化為“=”號;
(5)-9-2*5/-3+7/3*99/4*2998+10*568/14,這是上面整理得到的,下麵,我們對它進行分割處理,以“+-”進行分割,並且提取字元串中所有的“+-”,放在兩個列表中sign=["-","-","-","+","+"],formula_list = ["","9","2*5/","3","7/3*99/4*2998","10*568/14"];
(6)上面我們雖然得到了兩個列表,但是我們發現,formula_list中包含"",這個會影響我們後續的運算,列表中還包含"2*5/",說明這個地方的列表後面跟著一個負數,我們必須進行處理,把這個接上,這樣才能夠正確的運算;
(7)處理"",得到sign=["-","-","+","+"],formula_list = ["-9","2*5/","3","7/3*99/4*2998","10*568/14"]
(8)處理"2*5/",這裡要拼接後面的負數,得到sign=["-",,"+","+"],formula_list = ["-9","2*5/-3","7/3*99/4*2998","10*568/14"]
(9)下麵,我們來執行乘除運算,把列表formula_list傳遞給處理乘除的函數,讓裡面的乘除進行運算,得到如下格式;
(10)formula_list = ["-9",-3.33334,173134.00001,405.71],然後把這個列表返回回去,執行加減運算;
(11)處理加減的函數接到參數,並且執行加減運算,得到結果res;
(12)用res替換正則匹配出來的字元串,如上面程式一直迴圈,即可得到結果;
插入一個別人寫的代碼,這是我見過寫的最好的代碼,思路環環相扣,很考驗一個人的邏輯能力,思維能力,我看了幾遍弄到了原理,並且堅持自己謝了一遍。如下:
import re def operator_update(formula): # 對formula公式進行 去除空字元,更新運算符處理 formula = formula.replace(" ", "") # 去除空字元 formula = formula.replace("+-", "-") formula = formula.replace("--", "+") return formula def calc_muldiv(formula_list): ''' 計算公式裡面的乘除 :param formula: 列表 :return: ''' for index, element in enumerate(formula_list): if "*" in element or "/" in element: operators = re.findall("[*/]", element) calc_list = re.split("[*/]", element) num = None for i, e in enumerate(calc_list): if num: if operators[i - 1] == "*": num *= float(e) elif operators[i - 1] == "/": num /= float(e) else: num = float(e) formula_list[index] = num return formula_list def calc_plumin(operators, num_list): ''' 計算列表數字的加減 :param operators: 運算符列表 :param num_list: 進行運算的數字列表 :return: 返回計算結果 ''' num = None for i, e in enumerate(num_list): if num: if operators[i - 1] == "+": num += float(e) elif operators[i - 1] == "-": num -= float(e) else: num = float(e) return num def merge(plus_minus_operator, multiply_divide_list): ''' 把列表中這樣的形式'2*' '-3*' '5/3*' '4/2'合併到一塊 :param formula_list: :return: ''' for index, element in enumerate(multiply_divide_list): if element.endswith("*") or element.endswith("/"): multiply_divide_list[index] = element + plus_minus_operator[index] + multiply_divide_list[index + 1] del multiply_divide_list[index + 1] del plus_minus_operator[index] return merge(plus_minus_operator, multiply_divide_list) return plus_minus_operator, multiply_divide_list def bracket_calc(formula): ''' 對括弧最內層的formula公式進行計算 :param formula: :return: ''' formula = re.sub("[()]", "", formula) # 去除兩邊的() formula = operator_update(formula) plus_minus_operator = re.findall("[+-]", formula) # 列表 '+' '-' 運算符 multiply_divide_list = re.split("[+-]", formula) # 列表 有'*' '/' if multiply_divide_list[0] == "": # multiply_divide_list列表第一個字元為空的話,表示一個數字為負號 multiply_divide_list[1] = "-" + multiply_divide_list[1] del plus_minus_operator[0] del multiply_divide_list[0] res = merge(plus_minus_operator, multiply_divide_list) plus_minus_operator = res[0] # 列表 '+' '-' 運算符 進行合併處理 multiply_divide_list = res[1] plus_minus_list = calc_muldiv(multiply_divide_list) # 生成只進行加減運算的列表 res = calc_plumin(plus_minus_operator, plus_minus_list) return res def calculate(formula): '''計算程式主入口, 主要邏輯是先計算拓號里的值,算出來後再算乘除,再算加減''' while True: formula_depth = re.search("\([^()]+\)", formula) if formula_depth: formula_depth = formula_depth.group() res = bracket_calc(formula_depth) formula = formula.replace(formula_depth, str(res)) print("\33[34;1m%s\33[0m" % (formula)) else: res = bracket_calc(formula) print("\33[31;1m結果:%s\33[0m" % (res)) exit() if __name__ == '__main__': formula = "1 - 2 * ( (60-30 +(-9-2- 5-2*-3-5/3-40*4/2-3/5+6*3) * (-9-2-5-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) -(-4*3)/ (16-3*2) )" calculate(formula)
我在上面的思路上自己謝了一遍,沒有看代碼,自己按照思路謝了一遍,這個還要繼續研究,裡面用到了很多方法。字元串的分裂,findall()等很多方法,還有當元素不存在的時候,如果先創建,還有-=,+=,*=,/=等方法,元素裡面的值遍歷之後相乘相除的情況:
import re #導入正則模塊 formula = "1 - 2 * ( (60-30 +(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )" def formula_update(formula_deep): #對字元串formula_deep進行修整,去除空格,轉換+-為-,轉換--為+操作 formula_deep = formula_deep.replace(" ","") #去除空格 formula_deep = formula_deep.replace("+-","-") formula_deep = formula_deep.replace("--","+") return formula_deep def formula_correct(operator_signs,formula_list): if formula_list[0] == "": # 如果列表中第一個元素是"",說明元素前面是一個"-"號,此時,是沒有必要分割的,因為是-9,分割會出現錯誤,所以先進行判斷 formula_list[1] = "-" + formula_list[1] del operator_signs[0] del formula_list[0] print(operator_signs) print(formula_list) for i,e in enumerate(formula_list): if e.endswith("*") or e.endswith("/"): formula_list[i] = e + "-" + formula_list[i+1] del operator_signs[i] del formula_list[i+1] return operator_signs,formula_list def muldiv(formula_list): for index,element in enumerate(formula_list): if "*" in element or "/" in element: muldiv_signs = re.findall("[/*]",element) muldiv_lists = re.split("[/*]",element) num = None for i,e in enumerate(muldiv_lists): if num: if muldiv_signs[i-1] == "*": num *= float(e) elif muldiv_signs[i-1] == "/": num /= float(e) else: num = float(e) formula_list[index] = num return formula_list def add_min(operator_signs,formula_list): num = None for i,e in enumerate(formula_list): if num: if operator_signs[i-1] == "+": num += float(e) elif operator_signs[i-1] == "-": num -= float(e) else: num = float(e) return num def handle(formula_deep): formula_deep = re.sub("[()]", "", formula_deep) # 去除字元串的括弧,然後進一步執行,去除空格,以及轉換+-以及-- formula_deep = formula_update(formula_deep) # 對字元串進行修整,去除空格處理等 operator_signs = re.findall("[+-]", formula_deep) # 生成字元串中運算符的列表,因為要先執行乘法,要保留之前的運算符號,以便執行乘法後能夠執行加減 formula_list = re.split("[+-]", formula_deep) # 生成列表,列表的作用是執行運算的元素,列表中有一些不合理的地方需要修正 ret = formula_correct(operator_signs, formula_list) # 對列表進行修正,修正列表開頭元素是"",元素結尾是"/",或"*"的情況 operator_signs = ret[0] # 得到新的運算符號 formula_list = ret[1] # 得到新的運算列表 # 執行乘法運算 formula_list = muldiv(formula_list) # 得到不包含乘除的列表,下麵只需要執行加減即可 res = add_min(operator_signs, formula_list) return res def main(formula): while True: formula_deep = re.search("\([^()]+\)",formula) #匹配內層括弧,處理記憶體括弧中的內容,來回迴圈,即可滿足條件 if formula_deep: #匹配的內容不為空的時候執行程式,當匹配不到括弧的時候,說明已經匹配結束了,裡面不包含括弧了 formula_deep = formula_deep.group() res = handle(formula_deep) formula = formula.replace(formula_deep,str(res)) else: res = handle(formula) print(res) exit() if __name__ == "__main__": formula = "1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )" main(formula)
運行結果如下:
[]
['-40/5']
['-', '-', '+', '+']
['-9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']
['-', '-']
['60', '30', '8.0*173534.54761904766']
[]
['-4*3']
['-']
['16', '3*2']
['+']
['-1388246.3809523813', '12.0/10.0']
['-', '-']
['1', '2*', '1388245.1809523813']
result: 2776491.3619047627