python 计算器(四则运算)

学习来自:https://www.cnblogs.com/zingp/p/8666214.html  感谢!

 

思路:

  1. 考虑的四则运算符号 : ["+", "-", "*", "/", "(", ")"] 
  2. 获取表达式字符串 --》表达式切分 (请注意区分 减号"-", 与负号"-" )  --》
    1. 先出初切:
      formula_list = [i for i in re.split('(\-\d\.?\d*)', formula) if i]
      
      然后再判定:
      if re.search('[\+\-\*\/\(]$', final_formula[-1]):
    2. 其他正常切分就行:
      item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
      
  3.  得到合适的 字符子串  --》 区分 属于 数字栈 还是 操作符栈 -》存好后
  4. 运算逻辑
    1. 遍历表达式split后结果,如果数字来了需要压栈,进入 num_stack,
    2. 如果运算符来了,判定:
      1. 第一个运算符 直接压栈
      2. 新的后面的运算符来了,先拿出之前的运算符栈中最后的运算符弹出,比较优先级
        1. 如果优先级相同,数字栈弹出后两个元素与老运算符操作 ->  得到的结果压入数字栈
        2. 如果优先级不同,新的运算符压栈
        3. 注意,如果老运算符弹出为“(”, 新运算符目前为“)”,-> 弹出老的"(", 丢弃新的“)”
    3. 所有item结束后,数字栈和运算符栈中可能还有元素,再搞一波,最后结果在 num_stack中

 

代码:

import re

def calculate(n1, n2, operator):

    if operator == "+":
        result = n1 + n2
    elif operator == "-":
        result = n1 - n2
    elif operator == "*":
        result = n1 * n2
    elif operator == "/":
        result = n1 / n2
    else:
        raise Exception("operator is not support now...")
    return result


def is_operator(e):
    operators = ["+", "-", "*", "/", "(", ")"]
    return True if e in operators else False


def formula_format(formula):

    """
    步骤需要处理的是区分横杠‘-’是代表负数还是减号
    """

    formula = re.sub(' ', '', formula)

    # 以 '横杠数字' 分割, -> \- 表示匹配横杠开头; \d+ 表示匹配数字1次或多次;\.?表示匹配小数点0次或1次;\d*表示匹配数字1次或多次。
    formula_list = [i for i in re.split('(\-\d\.?\d*)', formula) if i]

    final_formula = []
    for item in formula_list:

        # 第一个是以横杠开头的数字(包括小数)final_formula。即第一个是负数,横杠就不是减号
        if len(final_formula) == 0 and re.search('^\-\d+\.?\d*$', item):
            final_formula.append(item)
            continue

        if len(final_formula) > 0:

            # 如果final_formal最后一个元素是运算符['+', '-', '*', '/', '('], 则横杠数字不是负数
            if re.search('[\+\-\*\/\(]$', final_formula[-1]):
                final_formula.append(item)
                continue

        # 剩下的按照运算符分割开
        item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
        final_formula += item_split

    return final_formula



def decision(tail_op, now_op):
    """
    :param tail_op: 运算符栈最后一个运算符
    :param now_op: 算式列表取出当前运算符
    :return: 1 弹栈, 0 弹出运算符栈最后一个元素, -1 入栈
    """
    # 运算符等级
    rate1 = ["+", "-"]
    rate2 = ["*", "/"]
    rate3 = ["("]
    rate4 = [")"]

    if tail_op in rate1:
        if now_op in rate2 or now_op in rate3:
            # 运算符优先级不同
            return -1  # 把当前取出的运算符压栈 "1+2+3"
        else:
            return 1  # 否则运算符栈中最后的 运算符弹出,进行计算

    elif tail_op in rate2:
        if now_op in rate3:
            return -1
        else:
            return 1

    elif tail_op in rate3:
        if now_op in rate4:
            return 0   # ( 遇上 ) 需要弹出 (,丢掉 )
        else:
            return -1  # 只要栈顶元素为(,当前元素不是)都应入栈
    else:
        return -1




# 主函数  ->  遍历算式列表中的字符,决定入栈弹栈操作
def final_cal(formula_list):

    num_stack = []
    op_stack = []
    for e in formula_list:
        operator = is_operator(e)
        if not operator:
            # 数字栈 ->  转为浮点数
            a = 2
            num_stack.append(float(e))
        else:
            # e 开始进入 运算符栈, -> 判断
            while True:
                a = 1
                if len(op_stack) == 0: #第一个运算符来了,都得入栈
                    op_stack.append(e)
                    break
                # 后面运算符来了,需要判断入栈,or 出栈。
                pop_oper = op_stack[-1]
                tag = decision(op_stack[-1], e)
                if tag == -1:  # 压栈
                    op_stack.append(e)
                    break
                elif tag == 0:  #弹出运算符栈内最后一个 "(", 丢掉当前的 ")", 进入下次循环
                    op_stack.pop()
                    break
                elif tag == 1:  # 运算符栈弹出最后一个运算符,数字栈弹出最后两个元素,进行计算
                    op = op_stack.pop()
                    num2 = num_stack.pop()
                    num1 = num_stack.pop()

                    # 计算后结果 --> 压入数字栈
                    num_stack.append(calculate(num1, num2, op))


    # 处理大循环结束后 数字栈和运算符栈中可能还有元素 的情况
    while len(op_stack) != 0:
        op = op_stack.pop()
        num2 = num_stack.pop()
        num1 = num_stack.pop()
        num_stack.append(calculate(num1, num2, op))
    return num_stack, op_stack





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))"
    formula = "1 - (2 + (-6 + (-2))) "
    formula_list = formula_format(formula)

    result, _ = final_cal(formula_list)
    print('result = ', result)




结果:

result =  [7.0]
 

你可能感兴趣的:(基础算法)