day4 作业计算器

作业:计算器开发

  (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   

posted @ 2017-05-21 21:43  (野生程序员)  阅读(405)  评论(0编辑  收藏  举报