1. 程式人生 > >python實現簡單計算器

python實現簡單計算器

import re


def remove_space(formula):
    """去掉算式的空格"""
    return formula.replace(" ", "")


def change_symbol(formula):
    """
    提取負號
    eg:-9-2-5-2*3-5/3-40*4/-1.0/5+6*3  ===>  -(9+2+5+2*3+5/3+40*4/1.0/5-6*3)
    """
    def primary_change(for_str):  # 把算式中的 + - 對應換成 - +
        temp = for_str.split("+")
        new_formula = []
        for value in temp:
            value = value.replace("-", "+")
            new_formula.append(value)
        return "-".join(new_formula)
    if formula.startswith("-"):
        formula = formula.replace("-", "", 1)
        formula = primary_change(formula)
        formula = formula.join(["-(", ")"])
    elif formula.startswith("+"):
        formula = primary_change(formula)
        formula = formula.join(["-(", ")"])
    else:
        formula = primary_change(formula)
        formula = formula.join(["-(-", ")"])
    return formula


def remove_repeat(formula):
    """去掉重複的運算子"""
    temp = formula.replace("++", "+")
    temp = temp.replace("+-", "-")
    temp = temp.replace("-+", "-")
    temp = temp.replace("--", "+")
    temp = temp.replace("*+", "*")
    temp = temp.replace("+*", "*")
    temp = temp.replace("/+", "/")
    temp = temp.replace("+/", "/")
    return temp


def has_special_operator(formula, special_operator):
    """判斷是否有 *+ +- /- 之類的運算子"""
    for operator in special_operator:
        if formula.find(operator) != -1:
            return operator
    return ""


def handle_special_operator(formula, operator):
    """
    如果有 "*-", "-*", "/-", "-/" 這些運算子,
    提取負號,去掉重複的運算子
    """
    temp = ""
    regex = "\d*[.]?\d+"
    opera = operator.replace("*", "[*]")
    ret = re.compile(opera.join([regex, regex]))
    while ret.search(formula):
        search_res = ret.search(formula).group()
        if operator.find("*") != -1:
            temp = search_res.replace(operator, "*")
        elif operator.find("/") != -1:
            temp = search_res.replace(operator, "/")
        temp = "-".join(["", temp])
        formula = formula.replace(search_res, temp, 1)
    return formula


def calculator_formula(formula):
    """
    計算算式,這裡計算的是不帶括號的算式
    計算次序是 / * - +
    計算過程中出現括號則停止計算,返回當前的算式
    """
    def primary_operator(for_str, operation):
        primary_result = 0
        regex = "\d*[.]?\d*"
        ret = re.compile(operation.join(["[", "]"]).join([regex, regex]))
        while ret.search(for_str):
            ret_opera = has_special_operator(for_str, ["*-", "-*", "/-", "-/"])
            while ret_opera:
                for_str = handle_special_operator(for_str, ret_opera)
                ret_opera = has_special_operator(for_str, ["*-", "-*", "/-", "-/"])
            while has_special_operator(for_str, ["+-", "-+", "++", "--", "+*", "*+", "+/", "/+"]):
                for_str = remove_repeat(for_str)
            # print("primary_operator:", for_str)
            if has_parentheses(for_str):
                return for_str
            if for_str.startswith("-"):
                temp = re.findall("^-\d*[.]?\d*$", for_str)
                if temp:
                    return temp[0]
                return change_symbol(for_str)
            if for_str.startswith("+"):
                for_str = for_str.replace("+", "", 1)
            if not ret.search(for_str):
                continue
            search_res = ret.search(for_str).group()
            operand_list = search_res.split(operation)
            if operation == "/":
                primary_result = float(operand_list[0]) / float(operand_list[1])
            elif operation == "*":
                primary_result = float(operand_list[0]) * float(operand_list[1])
            elif operation == "-":
                primary_result = float(operand_list[0]) - float(operand_list[1])
            elif operation == "+":
                primary_result = float(operand_list[0]) + float(operand_list[1])
            for_str = for_str.replace(search_res, str(primary_result), 1)
        return for_str
    formula = primary_operator(formula, "/")
    formula = primary_operator(formula, "*")
    formula = primary_operator(formula, "-")
    formula = primary_operator(formula, "+")
    return formula


def has_parentheses(formula):
    """判斷是否還有括號"""
    if re.search("[()]", formula):
        return True
    return False


def remove_parentheses(formula):
    """
    去掉算式的括號,計算括號裡算式
    """
    parentheses = re.compile("\([^()]+\)")
    while parentheses.search(formula):
        search_res = parentheses.search(formula).group()
        for_str = re.sub("[()]", "", search_res)
        if judge_illegal(for_str):
            return ""
        for_str = calculator_formula(for_str)
        formula = formula.replace(search_res, for_str, 1)
        # print("remove_parentheses:", formula)
    """
    會有去掉所有括號算式還沒算完的情況
    eg:1-2*65
    需要再計算一遍算式
    """
    formula = calculator_formula(formula)
    return formula


def judge_illegal(formula):
    """
    判斷括號是否匹配完全,運算子是否合法
    沒有考慮  **  //  的計算
    """
    if len(re.findall("[(]", formula)) != len(re.findall("[)]", formula)):
        return True
    if formula.startswith("*") or formula.startswith("/"):
        return True
    if has_special_operator(formula, ["*/", "/*", "**", "//"]):
        return True
    return False


def calculator_result(formula):
    """
    去完括號後額外計算的那一次若再次出現括號,
    則重複去括號運算,直至再沒有括號
    """
    formula = remove_space(formula)

    def first_calculator(for_str):
        if judge_illegal(for_str):
            return ""
        return remove_parentheses(for_str)
    formula = first_calculator(formula)
    while has_parentheses(formula):
        formula = first_calculator(formula)
        # print("calculator_result:", formula)
    if not formula:
        print("illegal formula!")
    return formula


f = "23 + 13 * ((25+(-9-2-5-2*3-6/3-40*4/(2-3)/5+6*3) * (9-2*6/3 + 5 *3*9/9*5 +10 * 56/-14 )) - (-4*3)/ (3+3*3) )"
print("result:", calculator_result(f))  # 輸出結果 13881.0
print("eval:", eval(f))  # 測試結果 13881.0