作业需求:
开发一个简单的python计算器:
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) ) 等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
作业总结
本次作业做了好几个版本,
一开始脑子是空白的,越看题目越傻了;
后来就想的整体写不出来,我留先写乘除加减的函数。结果第一版出来不支持负数,第二版支持负数;
最后又单独写去括号;
再将去括号和计算合并,可以实现作业的要求。后来发现代码只是仅仅可以实现作业的需求,和简单的正数类的运算;输入其他中间包含负数之类的就会产生计算错误,越写越没法收场了。。。
思路重新整理,通过网上查阅各版本思路,回过头来重新整理自己的套路及方法,历尽沧桑呀。
正确的答案请阅读片段:“作业思路重新整理”
作业思路
主要思路
1、找到最里边的括号
2、把加减和乘除放到函数里,不断的去调取。
具体思路
1、先写出乘除计算的函数,可以进行不包含括号的计算
2、再写出去括号的函数
3、合并代码
计算器流程图
乘除函数第一版:
#第一次完成,可以随便 乘 除 加 减 计算,但是不支持负数;
import re
def convert_list(a,arg):
list1 = [] #转换后的列表
num = ""
for i in a:
if num.isnumeric() and i.isdigit() :
list1.pop()
num = num + i
elif i == "-":
num = i
elif i == "." :
list1.pop()
num = num +i
elif num[-1:] == "." and i.isdigit():
print(num[-1:])
list1.pop()
num = num+i
else:
num = i
list1.append(num)
for i2 in list1:
arg.append(i2)
# print(a,"==",arg)
# return a
return arg
if __name__ == "__main__":
# a = "1+10.0*3.0/2-2"
a = input("please input Calculation formula:<1+3*2-1>:")
# 转换成列表
listlist = []
convert_list(a,listlist)
print(a,"===",listlist)
#计算乘除
while True:
print(a)
if "*" in listlist or "/" in listlist:
quzhi = re.search("\d+.\d+\*\d+\.\d+|\d+\.\d+\*\d+|\d+\*\d+\.\d+|\d+\*\d+|\d+.\d+\/\d+\.\d+|\d+\.\d+\/\d+|\d+\/\d+\.\d+|\d+\/\d+",a).group()
print(type(quzhi))
print(quzhi)
quzhi2 = []
quzhi2 = convert_list(quzhi,quzhi2)
print(type(quzhi),type(quzhi2))
print(quzhi2)
print(quzhi2[2])
print("=================")
result = float()
if "*" in quzhi2:
# print(True)
print(quzhi2.index("*"))
num3 = quzhi2.index("*")
list_n = quzhi2[0:num3]
print(list_n)
x = "".join(list_n)
list2_n = quzhi2[num3+1:]
y = "".join(list2_n)
print(x,y)
result = float(x) * float(y)
print(result)
re1 = listlist.index("*")
else:
result = float(quzhi2[0]) / float(quzhi2[2])
# print(listlist.index(quzhi2[1]))
# print(quzhi2)
re1 = listlist.index("/")
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.insert(re1-1,str(result))
print(listlist)
#给变量a 重新赋值
a = "".join(listlist)
print(a)
else:
break
while True:
print(a)
if "+" in listlist or "-" in listlist:
quzhi = re.search("\-\d+\*\d+|\-\d+\/\d+|\-\d+\+\d+|\-\d+\-\d+|\d+.\d+\+\d+\.\d+|\d+\.\d+\+\d+|\d+\+\d+\.\d+|\d+\+\d+|\d+.\d+\-\d+\.\d+|\d+\.\d+\-\d+|\d+\-\d+\.\d+|\d+\-\d+",a).group()
# quzhi = re.search(
# "\d+.\d+\+\d+\.\d+|\d+\.\d+\+\d+|\w+\d+\+\d\.\d+|\w+\d\+\d|\d+.\d+\-\d+\.\d+|\d+\.\d+\-\d+|\w+\d+\-\d\.\d+|\w+\d\-\d",
# a).group()
print(type(quzhi))
print(quzhi)
quzhi2 = []
quzhi2 = convert_list(quzhi, quzhi2)
print(type(quzhi), type(quzhi2))
print(quzhi2)
print(quzhi2[2])
print("=================")
result = float()
if "+" in quzhi2:
# print(True)
print(quzhi2.index("+"))
num3 = quzhi2.index("+")
list_n = quzhi2[0:num3]
x = "".join(list_n)
list2_n = quzhi2[num3 + 1:]
y = "".join(list2_n)
print(x, y)
result = float(x) + float(y)
print(result)
re1 = listlist.index("+")
else:
result = float(quzhi2[0]) - float(quzhi2[2])
# print(listlist.index(quzhi2[1]))
# print(quzhi2)
re1 = listlist.index("-")
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.insert(re1 - 1, str(result))
print(listlist)
# 给变量a 重新赋值
a = "".join(listlist)
print(a)
else:
break
乘除函数第二版:
# 乘 除 加 减 后 精简的,优化版本,支持负数;
#修复后支持负数,其实就是: 步骤一、字符串转列表 步骤二、正则匹配
import re
def convert_list(a,arg):
list1 = [] #转换后的列表
num = ""
for i in a:
if num.isnumeric() and i.isdigit() :
list1.pop()
num = num + i
elif i == "." :
list1.pop()
num = num +i
elif num[-1:] == "." and i.isdigit():
print(num[-1:])
list1.pop()
num = num+i
else:
num = i
list1.append(num)
for i2 in list1:
arg.append(i2)
if arg[0] == "-":
arg.insert(1,arg[0]+arg[1])
arg.pop(0)
arg.pop(1)
print(arg)
return arg
def ccjj(a,arg):
# 计算乘除
while True:
if "*" in listlist or "/" in listlist:
quzhi = re.search(
"\-\d+.\d+\*\d+.\d+|\-\d+.\d+\/\d+.\d+|\-\d+\*\d+|\-\d+\/\d+|\d+.\d+\*\d+\.\d+|\d+\.\d+\*\d+|\d+\*\d+\.\d+|\d+\*\d+|\d+.\d+\/\d+\.\d+|\d+\.\d+\/\d+|\d+\/\d+\.\d+|\d+\/\d+",
a).group()
quzhi2 = []
quzhi2 = convert_list(quzhi, quzhi2)
result = float()
if "*" in quzhi2:
num3 = quzhi2.index("*")
list_n = quzhi2[0:num3]
x = "".join(list_n)
list2_n = quzhi2[num3 + 1:]
y = "".join(list2_n)
result = float(x) * float(y)
re1 = listlist.index("*")
else:
result = float(quzhi2[0]) / float(quzhi2[2])
re1 = listlist.index("/")
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.insert(re1 - 1, str(result))
# 给变量a 重新赋值
a = "".join(listlist)
else:
break
while True:
if "+" in listlist or "-" in listlist:
quzhi = re.search(
"\-\d+.\d+\+\d+.\d+|\-\d+.\d+\-\d+.\d+|\-\d+\+\d+|\-\d+\-\d+|\d+.\d+\+\d+\.\d+|\d+\.\d+\+\d+|\d+\+\d+\.\d+|\d+\+\d+|\d+.\d+\-\d+\.\d+|\d+\.\d+\-\d+|\d+\-\d+\.\d+|\d+\-\d+",a).group()
quzhi2 = []
quzhi2 = convert_list(quzhi, quzhi2)
result = float()
if "+" in quzhi2:
num3 = quzhi2.index("+")
list_n = quzhi2[0:num3]
x = "".join(list_n)
list2_n = quzhi2[num3 + 1:]
y = "".join(list2_n)
result = float(x) + float(y)
re1 = listlist.index("+")
else:
num3 = quzhi2.index("-")
list_n = quzhi2[0:num3]
x = "".join(list_n)
list2_n = quzhi2[num3 + 1:]
y = "".join(list2_n)
result = float(x) - float(y)
re1 = listlist.index("-")
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.pop(re1 - 1)
listlist.insert(re1 - 1, str(result))
# 给变量a 重新赋值
a = "".join(listlist)
else:
break
return a
if __name__ == "__main__":
# a = "1+10.0*3.0/2-2"
while True:
a = input("please input Calculation formula:<1+3*2-1>:")
print(a)
# 转换成列表
listlist = []
convert_list(a,listlist)
print(listlist)
a = ccjj(a,listlist)
print("=================\n计算结果为:", a)
while True:
agin = input("\n您还要继续输入吗?<y/n>:")
if agin == "y":
break
elif agin == "n":
print("\n 谢谢光临!!")
exit()
else:
print("\n{输入错误,请重新输入!!}\n")
作业版本一:(去括号、加减乘除)
import re,sys
#字符串转列表函数 功能:输入的字符串格式的计算公式转换为列表的形式
def convert_list(a,arg):
list1 = [] #转换后的列表
num = ""
flag = 1
for i in a:
if i.isdigit() and num.isnumeric() :
list1.pop()
num = num + i
elif num.isdigit() and i == ".":
num = num + i
flag = 2
continue
elif num in "+-*/" and i == "-":
num = i
flag = 2
elif flag == 2 and i.isdigit():
list1.pop()
num = num + i
elif flag == 2 and i == ".":
list1.pop()
num = num + i
elif flag == 2 and i in "+-*/":
num = i
flag = 1
elif flag == 2 and i is not enumerate:
list1.append(num)
flag = 1
num = i
elif i.isdigit():
num = i
else:
num = i
list1.append(num)
for i2 in list1:
arg.append(i2)
return arg
#计算乘除加减函数 功能:传入计算公式的字符串和列表格式,进行判断计算
def ccjj(a,arg):
# 计算乘除
count = 0
while True:
if "*" in arg or "/" in arg:
quzhi = re.search(
"\-\d+\.\d+\*\d+\.\d+|\-\d+\*\d+\.\d+|\d+\*\d+|\-\d+\.\d+\/\d+\.\d+|\-\d+\/\d+\.\d+|\-\d+\.\d+\*\-\d+\.\d+|\-\d+\.\d+\*\-\d+|\-\d+\.\d+\/\-\d+\.\d+|\-\d+\.\d+\/\-\d+|\-\d+\/\-\d+\.\d+|\-\d+\/\-\d+|\d+\.\d+\*\-\d+\.\d+|\d+\.\d+\*\-\d+|\d+\*\-\d+\.\d+|\d+\*\-\d+|\d+\.\d+\/\-\d+\.\d+|\d+\.\d+\/\-\d+|\d+\/\-\d+\.\d+|\d+\/\-\d+|\d+\.\d+\*\d+\.\d+|\d+\.\d+\*\d+|\d+\*\d+\.\d+|\d+\*\d+|\d+\.\d+\/\d+\.\d+|\d+\.\d+\/\d+|\d+\/\d+\.\d+|\d+\/\d+|\d+\.\d+\*\-\d+\.\d+|\d+\.\d+\*\-\d+|\d+\*\-\d+\.\d+|\d+\*\-\d+|\d+\.\d+\/\-\d+\.\d+|\d+\.\d+\/\-\d+|\d+\/\-\d+\.\d+|\d+\/\-\d+",
a).group()
quzhi2 = []
quzhi2 = convert_list(quzhi, quzhi2)
print("乘除法取的值:",quzhi,quzhi2)
result = float()
if "*" in quzhi2:
result = float(quzhi2[0]) * float(quzhi2[2])
re1 = arg.index("*")
# print("乘法完之后:",result)
else:
result = float(quzhi2[0]) / float(quzhi2[2])
re1 = arg.index("/")
arg.pop(re1 - 1)
arg.pop(re1 - 1)
arg.pop(re1 - 1)
if float(result) < 0:
pass
else:
if float(quzhi2[2]) < 0 and count !=0:
print("retrun_a:::111", result)
# print(return_a)
return_a = str(-float(result))
print("retrun_a:::222", result)
if a[0] == "-" and count ==0 :
print("retrun_a:::11", result)
# print(return_a)
result = str(-float(result))
print("retrun_a:::22", result)
arg.insert(re1 - 1, str(result))
print("乘除法结果加入到列表:",arg)
# 给变量a 重新赋值
a = "".join(arg)
count +=1
else:
break
#计算加减
while True:
count = 0
if "+" in arg or "-" in arg:
quzhi = ""
try:
quzhi = re.search(
"\-\d+\.\d+\-\d+\.\d+|\-\d+\.\d+\-\d+|\-\d+\.\d+\+\d+\.\d+|\-\d+\.\d+\+\d+|\-\d+\+\d+\.\d+|\d+\+\d+|\-\d+\.\d+\-\d+\.\d+|\-\d+\-\d+\.\d+|\-\d+\.\d+\+\-\d+\.\d+|\-\d+\.\d+\+\-\d+|\-\d+\.\d+\-\-\d+\.\d+|\-\d+\.\d+\-\-\d+|\-\d+\-\-\d+\.\d+|\-\d+\-\-\d+|\d+\.\d+\+\-\d+\.\d+|\d+\.\d+\+\-\d+|\d+\+\-\d+\.\d+|\d+\+\-\d+|\d+\.\d+\-\-\d+\.\d+|\d+\.\d+\-\-\d+|\d+\-\-\d+\.\d+|\d+\-\-\d+|\d+\.\d+\+\d+\.\d+|\d+\.\d+\+\d+|\d+\+\d+\.\d+|\d+\+\d+|\d+\.\d+\-\d+\.\d+|\d+\.\d+\-\d+|\d+\-\d+\.\d+|\d+\-\d+|\d+\.\d+\+\-\d+\.\d+|\d+\.\d+\+\-\d+|\d+\+\-\d+\.\d+|\d+\+\-\d+|\d+\.\d+\-\-\d+\.\d+|\d+\.\d+\-\-\d+|\d+\-\-\d+\.\d+|\d+\-\-\d+",
a).group()
except:
pass
print("加减法取的值:",quzhi)
quzhi2 = []
quzhi2 = convert_list(quzhi, quzhi2)
# print(quzhi,quzhi2)
result = float()
if "+" in quzhi2:
result = float(quzhi2[0]) + float(quzhi2[2])
re1 = arg.index("+")
# print(result)
else:
result = float(quzhi2[0]) - float(quzhi2[2])
re1 = arg.index("-")
print("加减法得出的结果:",result)
arg.pop(re1 - 1)
arg.pop(re1 - 1)
arg.pop(re1 - 1)
if float(result) <= 0:
pass
else:
if float(quzhi2[2]) < 0 and count != 0:
print("retrun_a:::111", result)
# print(return_a)
return_a = str(-float(result))
print("retrun_a:::222", result)
if a[0] == "-" and count ==0 :
print("retrun_a:::11", result)
# print(return_a)
result = str(-float(result))
print("retrun_a:::22", result)
arg.insert(re1 - 1, str(result))
# 给变量a 重新赋值
a = "".join(arg)
count =+1
# print("***:",arg)
if len(arg) < 3:
break
else:
break
return a
#去括号函数 功能:把输入的公式先计算括号里边的内容
def qukuohao(a,arg):
listlist = []
convert_list(a,listlist)
countcount = 1
while True:
print("\033[32m[[第%s次计算前:]]\033[0m"%(countcount),a)
try:
index1 = listlist.index(")")
# print("查看)的第几个位置:",index1)
# print(len(listlist))
except:
pass
for i in range(index1,-1,-1):
try:
if listlist[i] == "(":
new_list = listlist[i+1:index1] #获取括号里的内容
# print("new_list括号里的内容-列表形式---:",new_list) #打印获取括号里的内容,不包括括号
# print(listlist[i:index1+1])
del_count = len(listlist[i:index1+1]) #获取括号以及括号里的内容的长度,用于后边listlist.pop()
# print("del_count",del_count) #打印上边的长度
#以下if判断用于 判断括号里是否有计算公式,没有就删除listlist列表里的括号及里边内容并插入计算结果,再进行下次循环;
if len(new_list) < 3: #如果new_list的长度小于3,代表括号里边没有计算公式了;
a = "".join(new_list) #接下来可以直接去掉括号
listlist.pop(index1 - 2)
listlist.pop(index1 - 2)
listlist.pop(index1 - 2)
listlist.insert(index1 - 2,a) #去掉括号后,把括号里边的内容插入到listlist列表
# print("重新整理后的列表", listlist)
break
new_a = "".join(new_list) #括号里边的内容转化成字符串,为了运行 convert_list函数做准备
nn_list = [] #定义括号里的字符串内容转换后 用作的列表
#运行 字符串转成列表函数
convert_list(new_a,nn_list) #转换括号里的字符串new_a成新的列表nn_list
#运行 乘除加减函数
return_a = ccjj(new_a,nn_list) #将括号里的字符串形式 和 括号里字符串列表形式 传进去计算;结果return给a
#判断 删除括号以及括号里边的内容的次数,并删除括号以及括号里边的内容
count = 0
for i in range(0,del_count):
# print("----listlist前:", listlist)
if count >= del_count:
break
else:
listlist.pop(index1 - (del_count-1))
count += 1
#将括号里边计算出来的结果 加入到listlist列表中
listlist.insert(index1-(del_count-1),return_a)
a = "".join(listlist)
print("\033[31m[[第%s次计算后:]]\033[0m" % (countcount), a)
countcount += 1 #用于打印去括号计算的次数
break
except:
pass
else:
break
#如果计算到最后列表里边没有括号了,直接进行 乘除加减 计算
a = ccjj(a,listlist)
# print("\033[34m最后的计算结果是:%s\033[0m"%a)
print("\033[31m[[第%s次计算后:]]\033[0m" % (countcount), a)
return a
if __name__ == "__main__":
# a = "1-(5*2-5*3/2)+10"
count = 0
while True:
msg = "------------------------------------------------------------------------------\n" \
"请输入计算公式:\n" \
"如①:<1+3*2-1>\n" \
"如②:1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))\n" \
"------------------------------------------------------------------------------"
print(msg)
a = input("\033[42m please input Calculation formula:\033[0m")
a = a.replace(" ", "") # 去空格
if count < 3:
# 转换成列表
listlist = []
if "(" in a:
#去括号
a = qukuohao(a,listlist)
else:
convert_list(a, listlist)
# print(listlist)
# print(a)
a = ccjj(a, listlist)
p = len(a) + 20
for i in range(p):
sys.stdout.write("#")
sys.stdout.flush()
# time.sleep(0.1)
sys.stdout.write("\n")
print("\033[34m最后的计算结果是:%s\033[0m"%a)
for i in range(p):
sys.stdout.write("#")
sys.stdout.flush()
# time.sleep(0.1)
sys.stdout.write("\n")
elif count > 2 :
agin = input("\n您还要继续输入吗?<y/n>:")
if agin == "y":
break
elif agin == "n":
print("\n 谢谢光临!!")
exit()
else:
print("\n{输入错误,请重新输入!!}\n")
存在问题
只支持作业上的计算和简单的加减计算;
1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
但是计算公式中间有负数之类的就会计算错误:
例如:1-(5*2-5*3/2)+10 计算结果正确是8.5
作业思路重新整理
1、加减乘除正则匹配重新整理;
2、计算结果替换 用上x.replace(source,dest) ;
3、字符串转列表循环修复;
4、去括号
获取括号里边的内容用正则匹配,而不是for循环;
计算结果替换 用上x.replace(source,dest) ;
5、用户输入公式后,先判断输入的是否包含非公式的不规则字符,有则提示“输入错误!”;
6、用户输入公式后,判断输入的字符串是否包含计算公式,不包含则不进入计算函数;
7、关键问题:将所有的加和减,都以加的形式计算;
例如:9-2*5 再匹配乘除计算的时候先是:-2*5;然后再9+-10
思路重新整理之前的问题:
1、正则匹配没有精简,也没有最佳匹配;
2、字符串转列表存在缺陷;
3、可能出现的公式形式没有想的周全,有些偏面;
4、知识点没能够合理运用,字符串替换;
5、最大问题是没有想清楚有负数的各种形式时候如何计算;
最终作业版本
#!/bin/bash/env python#_*_ coding:utf-8 _*_#python version: 3.x#author: 506554897import#字符串转列表函数def convert_list(a,arg):#转换后的列表""10forinifandelifand"."2continueelifin"+-*/"and"-"2elif2andelif2and"."elif2andin"+-*/"1elif2andisnot1elif0and"+"continueelifelse1forin# print("转成列表后的字符串和列表:",a,arg)return#加减乘除函数def jjcc(a):#乘除循环whileTrueif"*"inor"/"in"\+?\-?\d+\.?\d*[*|/]\-?\d+\.?\d*"#用于保存正则取值后的列表# print("乘除取到的值:",quzhi,type(quzhi),type(quzhi2),quzhi2)if1"*"02elif1"/"02if0#用于结果是 +8 类似的,给取绝对值,去掉+ ;"+"else# print("乘除替换后的值:",a)elsebreak#加减循环whileTrue#判断字符串是否还有计算公式的存在#判断字符串 里边是否已经没有 加减乘除 的公式 的列表if3#如果judge列表元素的长度小于3,代表已经没有计算公式了if0#用于结果是 +8 类似的,给取绝对值,去掉+ ;# print("最后的结果:",a)breakif"+"inor"-"in"\+?\-?\d+\.?\d*[+|-]\-?\d+\.?\d*"# print("加减取的值:",quzhi,type(quzhi),quzhi2,type(quzhi2))if1"+"02elif1"-"02# print("加减后的值:",a)elsebreakreturn#去括号函数def remove_parenthesis(a):#去括号循环1# 用于计算进行了几次去括号whileTrueif")"in"\033[32m[[第%s次括号计算前:]]\033[0m""\([^()]+\)"# print(quzhi)"()"#去掉字符串里边的"()"# print("去括号取到的值:",quzhi2)#运行加减乘除函数,进行计算#将计算结果替换前边正则匹配的字符串# print("<<去括号替换后的结果:>>",a)elsebreak"\033[31m[[第%s次括号计算后:]]\033[0m"1# 用于打印去括号计算的次数returnif"__main__"# a = "1+10.0*3.0/2-2"0#计算用户输入的公式次数whileTrue"------------------------------------------------------------------------------\n""\033[31m输入计算公式例子:\n\033[0m""如①:1+3*2-1\n""如②:1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))\n""------------------------------------------------------------------------------""\033[47m please input Calculation formula:\033[0m"" """# 去空格#判断是否输入计算公式以外的字符,例如中文、字母try"[^+|\-|*|/|(|)|\d]+"ifisnotNone# 如果输入字符串包含不规则就提示输入错误!!"\033[41m输入错误!!!\033[0m"continueexceptpass#判断输入公式的次数if3# 检查输入的是否是公式# 判断字符串 里边有没有 加减乘除 的公式 的列表if3#如果judge的元素小于3,代表输入的字符串没有计算公司if00#如果输入的+8 进行绝对值把 + 去掉"\033[31m输入的没有计算公式!\033[0m"# 如果输入的字符串有公式else#去括号"\033[32m<<去完括号后的结果:>>\033[0m"#统计“最后的计算结果是:XX”字符串的长度;“最后的计算结果是:”的长度是20 + a的长度20#根据p的长度打印 n个#forin"#"# time.sleep(0.1)"\n"#打印计算结果"\033[34m最后的计算结果是:%s\033[0m"# 根据p的长度打印 n个#forin"#"# time.sleep(0.1)"\n\n"#如果输入公式次数大于3次提示是否继续输入elif2"\n您还要继续输入吗?<y/n>:"if"y"breakelif"n""\n 谢谢光临!!"else"\n{输入错误,请重新输入!!}\n"
,如需转载请自行联系原作者