python 简单计算器递归算法 多层括号处理

用python编写一个简单计算器

计算器开发需求 实现加减乘除及拓号优先级解析 用户输入 # 1 – 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) – (-4*3)/ (16-3*2) ) # 等类似算式后,必须自己解析里面的(),+,-,*,/符号和公式,利用递归算法

拿到这个题目时,感觉无从下手。老师说利用开学来3天学习的知识是可以做出来的。然后我认真归纳总结前3天学习的基础知识,经过3天3夜的奋战终于给弄出来了。虽然中途也有想过放弃,但是没有耕耘哪来的收获。如果初学的同学想借鉴的话, 建议自己先仔细想想,如果实在无从下手可以参考下我的。特写此文以自勉。程序中可能出现很多冗余或bug,望勿见笑。下面我先说说我的思路。

  1. 先构造几个函数方法用来进行最初的运算(加减乘除)
  2. 在运算函数中,先传入一个字符串,将字符串利用正则表达式,findall函数生成可以取元素的列表形式,利用返回值,
  3. 先进行加法和减法运算,加减法能顺利通过验证,结果无误
  4. 在算式中增加乘法和除法,用if语句进行判断,如果有乘法和除法,需优先进行计算,通过验证后
  5. 在算式中增加括号,增加括号后,需要进行for循环遍历,如果遍历的元素中包含括号,则优先处理计算括号里面的
  6. 利用列表临时存储返回值,赋给原来的算式,进行递归,这样算式越来越精简。最终得出结果。

简单流程图如下:
《python 简单计算器递归算法 多层括号处理》

以下是实现代码:

#!/usr/bin/env python
#-*-coding:utf-8 -*-

import re
# 定义函数
def add(x , y): #相加
    return x + y
def subtract(x, y): #相减
    return x - y
def multiply(x, y):  #相乘
    return x * y
def divide(x, y): #相除
    return x / y

temp=[0] #定义一个临时列表,并且赋值0,用来存储结果
temp1=[] #定义一个临时列表,用来临时存储列表
def sum2(ret):  #定义一个函数用来进行数据的处理,运算
    for index,mark in enumerate(ret):  #遍历列表,赋值给mark
        if  str(mark).count("(")==1 and str(mark).startswith("("):  #如果mark中包含“(”并且以其开头
            ret.pop(index)  #将该值(mark),在列表中移除
            mark1=re.findall('^\(\-[0-9.]+|[0-9.]+|[*/+]|[-]',mark)  #将mark元素,再次生成列表
            h = float(re.sub('\(', '', mark1.pop(0)))  #将该表的第一个元素取出,并且将其中所包含的括号替换移除
            mark1.insert(0,h)  #将重新得到的元素,重新插入列表中
            sum2(mark1)  #调用递归算法,计算该列表
            ret.insert(index,temp[-1]) #将临时存储数据的列表的最后一个元素,插入当前循环的索引位置
        elif str(mark).count("(") >= 1:  #如果mark元素中的括号熟练大于等于1
            mark2 = re.findall('\([^()]+\)', mark) #将mark 元素去除最外层括号
            t2=mark2[0]
            mark3 = re.findall('\((.+)\)', mark2[0]) #将mark 元素去除最外层括号
            r1=re.findall('^\(\-[0-9.]+|[0-9.]+|[*/+]|[-]', mark2[0]) #将mark2生成可以计算的列表形式
            h = float(re.sub('\(', '', r1.pop(0)))  #如果r1 包含括号减号则将括号移除
            r1.insert(0, h)
            r2=re.findall('^\(\-[0-9.]+|[0-9.]+|[*/+]|[-]', mark3[0]) #将mark3生成可以计算的列表形式
            mark4=r1 if str(t2).count("(-")==1 else r2  #进行三目运算,判断mark2(t2)是否包含括号,不同的值赋给mark4
            temp1.clear()  #如果临时存储temp1中有数据,则清空
            temp1.extend(ret)  #算式赋值给临时存储temp1
            sum2(mark4)   #调用递归算法,计算该列表
            q4 = mark.replace(str(mark2[0]), str(temp[-1]))  #将结果值替换该运算位置,赋值给q4
            if str(q4).count("(") >= 1:  #如果字符串q4中,包含括号的数量大于等于1
                ret.pop(index)  #将索引位置移除
                ret.insert(index,q4)  #将新得到的字q4
                sum2(ret)  #调用递归算法,计算该列表
            else:  #如果不存在括号
                ret.pop(index)  #将索引位置移除
                rr = re.findall('[0-9.]+|[*+\-/]+|\([^()]+\)+|\(.+\)+', q4)  #采用正则重新生成可以可以计算列表形式
                for index11, wor in enumerate(rr):   #循环打印 rr中的元素
                    if len(wor) == 2 and wor in "+-*/":  #如果元素wor的长度等于2 并且包含于 符号 "+-*/",就是同时出现两个运算符号,其中有一个减号
                        rr.pop(index11)  #移除该索引的元素
                        rr.insert(index11, wor[0])  #将wor元素的第一个运算符插入原来的位置
                        rrr = rr.pop(index11 + 1)  #将下一个索引元素移除
                        rr.insert(index11 + 1, wor[1] + rrr)  #将wor元素的第二个运算符与当前索引的下一个元素合并
                        sum2(rr)  #调用递归算法,计算该列表
                        q4=temp[-1]  #将结果值赋值给q4,就是更新q4 (这里经过计算后,q4 是一个数字了)

                ret.insert(index,q4)  # 将q4 插入到当前运算式的位置
                if len(ret)==3:  #如果运算式的长度为3, 说明可以进行运算
                    sum2(ret) #调用递归算法,计算该列表
                elif ret[0]=="-":  #如果运算式的第一个字符为减号,则跳过
                    pass
                elif len(ret)>=3 and q4.isalnum()==False:  #如果运算式的长度等于大于3 并且包含非数字(包含运算符)
                    q5=re.findall("[[0-9.]+|[+\-*/]",q4)  #将q4 生成可以计算的列表形式
                    sum2(q5)  #调用递归算法,计算该列表
                    ret.pop(index) #将当前索引元素移除
                    ret.insert(index,temp[-1])  #将计算出的结果值插入当前位置
                    if len(ret)>=3:  #如果算式的长度还大于等于3
                        sum2(ret)  #则继续递归

        #elif mark == "*" or mark=="/":
        elif str(mark) in "*/":  #如果字符串元素中包含运算符 */乘法 和除法
            if (len(ret))>=3:  #如果算式长度大于等于3
                x=float(ret.pop(index-1))  #取出一个元素并移除,转化为浮点型
                i=ret.pop(index-1)  #取出一个元素并移除 这个是 运算符
                y=ret.pop(index-1) #取出一个元素并移除,转化为浮点型
                y11=y  #将y赋值给y11
                if "(" in str(y):
                    y12 = re.findall('\([^()]+\)', y11)  #说明该元素中还包含括号,需要继续运算
                    for index12, gg in enumerate(y12):  #遍历该元素
                        t2 = y12[0]
                        r1 = re.findall('^\(\-[0-9.]+|[0-9.]+|[*/+]|[-]', y12[0])
                        y14 = re.findall('\((.+)\)', y12[0])
                        h = float(re.sub('\(', '', r1.pop(0)))
                        r1.insert(0, h)
                        r2 = re.findall('^\(\-[0-9.]+|[0-9.]+|[*/+]|[-]', y14[0])
                        # mark4 = str(t2).count("(-")==1 ? r1:r2
                        y13 = r1 if str(t2).count("(-") == 1 else r2  #三目运算

                        sum2(y13)
                        y11 = y11.replace(str(y12[0]), str(temp[-1]))
                        y12.pop(0)
                        y12.append(temp[-1])
                        y15 = re.findall('[0-9.]+|[*+/]|\([^()]+\)+|\(.+\)+|[\-]', y11)
                        sum2(y15)
                        y=temp[-1]  #将最终结果数字赋给y

                y=float(y)  #转化为浮点型

            if  str(mark)=="*":  #如果元素mark 包含乘号 *
                s=multiply(x,y)  #调用乘法计算公式
                ret.insert(index-1,s)  #将结果插入当前索引算式的位置
                temp.append(s)   #将乘积存储在临时列表中
                if len(ret)>=3:   #如果算式列表的长度还大于等于3
                    sum2(ret)   #调用递归算法,计算该列表
            if str(mark) == "/": #如果元素mark 包含除号 /
                s=divide(x,y)
                temp.append(s)
                ret.insert(index - 1, s)
                if len(ret)>=3:
                    sum2(ret)

    if len(ret)>=3:   #如果算式列表的长度还大于等于3
        x=ret.pop(0)  #取出移除第一个元素
        w2 = re.findall('[0-9.]+|[+\-*/]', str(x))  #将该元素生成可以计算的列表形式
        if str(x)=="-":  #如果x中包含 -号
            x=str(x)+str(ret.pop(0)) #将当前和下一个元素合并 (形成负数)
        if len(w2) >= 4:  #如果x中包含多个算式
            sum2(w2)  #调用递归算法,计算该列表
            x = temp[-1]  #将计算的结果赋给x

        x=float(x)
        i=ret.pop(0)
        y=ret.pop(0)
        if str(y)=="-":
            y=y+str(ret.pop(0))
        y =float(y)
        if i in "*/()":
           return
        else:
            if i in "+":  #如果i包含 加号+
                s = add(x, y)
                temp.append(s)
            elif i in "-":  #如果i包含 加号-
                s= subtract(x,y)
                temp.append(s)
        s=temp[-1]  #将得出的结果赋给s
        if len(ret) >= 2:  #算式的长度大于等于2,说明还要继续计算
            ret.insert(0,s)  #将该结果插入到算式中
            sum2(ret)
    return temp[-2]  #将临时数值列表中的 最后一个值返回,该值就是最终结果

def sum():
        arg = input("请输入算式(只能包含数值,小括号,+-*/):")  #输入提示
        print("您输入的算式为:", arg)
        arg = re.sub('\s', '', arg) #将空格全部替换
        arg1= re.match('[(\).+\-*/0-9]+$', arg)  #判断输入的是否符合要求

        if arg1: #如果符合要求,则执行下一步
            #print(arg1.group())
            pass
        else:  #如果不符合,重试进入程序
            print("您输入的包含非法字符,请重新输入!")
            arg=""
            sum()

        if str(arg).count("(")!=str(arg).count(")"):  #如果输入的括号对 数量不对,重新输入
            print("您输入的括号对数有误,请重新输入!")
            arg = ""
            sum()
        arg2="'"+arg+"'"
        #print("计算机结果为:",eval(arg2))
        ret=re.findall('\(.*\)|[0-9.]+|[*/+]|[-]',arg)  #将字符串初始成可以计算的列表形式
        j=sum2(ret)  #调用函数
        return j

x1 = sum()  #调用函数
print("结果:", x1)

完毕!

    原文作者:递归算法
    原文地址: https://blog.csdn.net/qwer12347070/article/details/78755860
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞