练习-表达式计算(多层括号,加,减,乘,除,整除,取余,幂)

import re

# 运算字典
calc = {
    '+': lambda x, y: x + y,  # 加
    '-': lambda x, y: x - y,  # 减
    '*': lambda x, y: x * y,  # 乘
    '/': lambda x, y: x / y,  # 除
    '%': lambda x, y: x % y,  # 取余数
    '//': lambda x, y: x // y,  # 整除
    '^': lambda x, y: x ** y  # 幂(不知道是不是bug,方式不同结果不同,最下面有演示)
}


# 判断优先级函数
def order(lis=[]):
    # 列表开头有'-'说明第一个数是负数
    if lis[0] == '-':
        lis.pop(0)
        lis[0] = -float(lis[0])
    while len(lis) != 1:  # 未得到最终结果就继续执行
        for i in range(len(lis)):
            # 判断是否运算符
            muldiv = re.search(r'[\^*/%+-]/?$', str(lis[i]))
            if muldiv:
                # 判断当前是否加,减运算
                if re.search(r'[+-]', str(lis[i])):
                    # 判断后续是否有优先级高的幂,乘,除,求余,整除运算
                    if re.search(r'[\^*/%]/?', str(lis)):
                        continue
                # 判断当前是否乘,除,求余,整除运算
                elif re.search(r'[*/%]/?', str(lis[i])):
                    # 判断后续是否有优先级高的幂运算
                    if re.search(r'[\^]', str(lis)):
                        continue
                num1 = float(lis[i - 1])  # 取参数1
                # 在i是符号的情况下,出现'-',说明下个数是负数,
                if lis[i + 1] == '-':
                    lis.pop(i + 1)
                    lis[i + 1] = -float(lis[i + 1])
                num2 = float(lis[i + 1])  # 取参数2
                result = calc[muldiv.group()](num1, num2)  # 按运算符进行运算
                for m in range(2):  # 删除已运算完的表达式
                    lis.pop(i)
                lis[i - 1] = result  # 将结果加入表达式
                break  # 返回重新开始,因为索引位置已发生改变,不适合继续取值
    return lis


# 主函数
def operation(exp):
    # 统一格式化表达式
    exp = exp.replace(' ', '').replace(')(', ')*(')
    exp = exp.replace('++', '+').replace('--', '+')
    exp = exp.replace('+-', '-').replace('-+', '-')
    exp = exp.replace('**', '^')
    # 正则分割字符串
    exp = re.findall(r'\d+(?:\.\d+)?|[\D+]/?', exp)
    while '(' in exp:  # 判断有没有括号
        # 用循环来寻找匹配的括号,执行完括号内表达式就退出循环
        for i in range(len(exp)):
            if exp[i] == '(':
                if i > 0 and re.search(r'\d+(?:\.\d+)?', str(exp[i - 1])):
                    exp.insert(i, '*')  # 将类似2()形式的,改成2*()形式
                    break
                start = i  # 记录最后一个"("位置
            elif exp[i] == ')':
                fir = exp[:start]  # 切片列表左边
                mid = exp[start + 1:i]  # 切片要计算的中间列表
                end = exp[i + 1:]  # 切片列表右边
                mid = order(mid)  # 判断优先级计算,得出计算结果
                exp = fir + mid + end  # #将括号内表达式计算完后,进行列表拼接
                print(str(exp).replace(',', '').replace("'", ''))
                break
                # 跳出for循环,不再进行下一组括号计算(因为原列表已改变,索引也改变,不适合下次取值)
    else:  # 没括号,直接执行计算
        order(exp)
    return float(exp[0])

if __name__ == '__main__':
    l = "-2.5*((3.562**2 + 5*-60//-2)*(3*-5/6-9%-10//3))"
    # 分解步骤如下
    # - 2.5 * (162.68784399999998 * (3 * - 5 / 6 - 9 % - 10 // 3))
    # - 2.5 * (162.68784399999998 * -1.5)
    # - 2.5 * -244.03176599999998
    # 610.0794149999999
    ret = operation(l)
    print('内置函数:%s' % eval(l))
    print('自写函数:%s' % ret)


    # 同样都是幂运算,结果却不相同
    num1 = -3.562
    num2 = 8
    print('eval:%F     数字:%F    变量:%F    POW:%F' %
          (eval('-3.562**8'), -3.562**8, num1**num2, pow(-3.562, 8)))

  

posted @ 2017-03-12 21:19  破斧呈粥  阅读(350)  评论(0编辑  收藏  举报