用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,望勿见笑。下面我先说说我的思路。
- 先构造几个函数方法用来进行最初的运算(加减乘除)
- 在运算函数中,先传入一个字符串,将字符串利用正则表达式,findall函数生成可以取元素的列表形式,利用返回值,
- 先进行加法和减法运算,加减法能顺利通过验证,结果无误
- 在算式中增加乘法和除法,用if语句进行判断,如果有乘法和除法,需优先进行计算,通过验证后
- 在算式中增加括号,增加括号后,需要进行for循环遍历,如果遍历的元素中包含括号,则优先处理计算括号里面的
- 利用列表临时存储返回值,赋给原来的算式,进行递归,这样算式越来越精简。最终得出结果。
简单流程图如下:
以下是实现代码:
#!/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)
完毕!