此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631]
代码的git地址[https://e.coding.net/sxl357/f4.git]
git地址下的功能1.py和功能1.exe用来完成功能1,f4.py和f4.exe用来完成功能2和功能3.
功能1. 四则运算
支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答
> f4 1+2*3+4= ?11 答对啦,你真是个天才! 1+2*3+5= ?11 再想想吧,答案似乎是12喔! 1+2/4-5= ?-3.5 答对啦,你真是个天才! ...(一共20道题) 你一共答对4道题,共20道题。重难点:1.给定一个运算式,如何让计算机算出结果?给定的运算式属于中缀表达式,将其改为后缀表达式,再计算结果。(1)中缀转后缀
#将中缀表达式转为后缀表达式
def make_Expression(s):
operations=[]
result=''
front={'+':1,'-':1,'*':2,'/':2}
for i in s:
if i in ['+','-','*','/']:#判断是否是操作符
if len(operations)==0:#栈空,直接入栈
operations.append(i)
elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别
while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别
p=operations.pop()
result+=p
operations.append(i)
else:
operations.append(i)
else:
result+=i#若是数,直接输出
while len(operations)>0:#将栈中的所有元素依次弹出
p=operations.pop()
result+=p
return result#返回后缀表达式
(2)计算后缀表达式
#计算后缀表达式
def make_Value(s):
lists=[]
for i in s:
if i in ['+','-','*','/']:
b=float(lists.pop())#先弹出的是b,下个弹出的是a
a=float(lists.pop())
c=0
if i=='+':#判断做哪则运算
c=a+b
elif i=='-':
c=a-b
elif i=='*':
c=a*b
else:
c=a/b
lists.append(c)#得到的结果压入栈中
else:
lists.append(i)
return lists[0]
2.如何随机生成运算式(3个运算符,4个操作数)?
这对于我们来说是个大问题,查资料,询问 师哥师姐,了解到random.randint(a,b)用于生成一个指定范围内的整数n
#随机生成运算式
from random import randint #random.randint(a,b)用于生成一个指定范围内的整数n,其中a<=n<=b
# 定义类
class Expression:
# 生成运算式
def expre(self):#在类里定义函数必须传入self,指的是类实例对象本身
exp = []
for j in range(0,7): #range(a)=[0,1,2,3,...,a-1]
if j % 2 != 0:#通过模2,生成带3个运算符4个10以内数字的表达式
operators = ['+', '-', '*', '/']
exp.append(operators[randint(0, len(operators) - 1)]) #随机生成运算符
else:
exp.append(str(randint(1, 9))) #随机生成操作数
expression = ''.join(exp)
return expression
generate=Expression() #定义对象 expression = generate.expre()#调用generate()函数,生成运算式
3.如何循环出题,并验算结果,给出反馈?
先生成运算式,然后调用转后缀,计算后缀的函数 ,得到正确结果,与用户输入的对比,给出反馈,循环20次,并利用全局变量累积答对的题的数目。
#出20道考题,判断用户结果是否等于正确答案,实现功能一
def question():
num = 0
global correctNumber # 定义全局变量,统计答对的次数
while num <20:
generate=Expression() #定义对象
expression = generate.expre()#调用generate()函数,生成运算式
print(expression + "=")
expression1 = make_Expression(expression) # 将中缀表达式转换为后缀表达式
result = make_Value(expression1) # 计算后缀表达式的值
userAnswer = input() # 输入你的答案
if '?' in userAnswer:
userAnswer = userAnswer.replace('?', '')#str.replace(old,new,max)方法,把字符中的old替换成new,且替换不超过max次
if (float(userAnswer) == float(result)): # 判断用户结果是否和正确答案相等
correctNumber += 1
print("答对了,你真是个天才!")
else:
result = str(result)
print('再想想吧,答案似乎是' + result + '喔!')
num += 1
correctNumber = str(correctNumber)
print("你一共答对" + correctNumber + "道题,共20道题。")
4.如何定义此时的主函数?
#定义主函数
def main(argv):
question()#实现功能一
#主函数
if __name__ == "__main__":
main(sys.argv[1:])
运行测试截图


功能2 支持括号
> f4 1+2*(3+4)= ?15 答对啦,你真是个天才! (1+2)*3+5= ?11 再想想吧,答案似乎是14喔! ((1/2)-4)*5= ?-17.5 答对啦,你真是个天才! ...(一共20道题) 你一共答对4道题,共20道题。
重难点
1.中缀转后缀时,有括号怎么办?
左括号可以直接入栈,但遇到右括号时,遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号
for i in s:
if i in ['+','-','*','/','(',')']:#判断是否是操作符
if i=='(':#遇到左括号,将其直接放入栈中
operations.append(i)
elif i==')':#遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号
while (len(operations)>0 and operations[-1]!='(' ):#-1表示列表的最后一个元素,即栈顶
p=operations.pop()
result+=p
operations.pop()#左括号只弹出不输出
elif len(operations)==0:#栈空,直接入栈
operations.append(i)
elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别
while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别
p=operations.pop()
result+=p
operations.append(i)
else:
operations.append(i)
else:
result+=i#若是数,直接输出
2.何时何地生成括号?
在生成运算式的类中,生成了不带括号的运算式后,随机生成0或1,0就表示不插入括号,1表示插入括号,此时调用生成括号的函数,在该函数中,用枚举法确定括号的位置,然后根据随机数选择其中一种,将括号插入,最后返回带括号的表达式。
is_need_brackets = randint(0, 1) # 判断是否要括号
if is_need_brackets:#添加括号
expression = ''.join(self.make_brackets(exp))#.join()将序列中的元素以指定的字符连接生成一个新的字符串
#加括号时,调用生成括号表达式的函数,得到一个带括号的运算式
else:#不添加括号
expression = ''.join(exp)
# 生成括号表达式
def make_brackets(self,exp):#传入由运算符和数字组成的列表
expression = []
# 可能有一对括号,也可能有两对括号,所以最多有11个位置可以添加括号
#经过枚举,共有10种可能的添加方式
# 0表示直接将运算符或数字传入生成式,1表示在生成式加入左括号,2表示在生成式加入右括号,-1表示不作任何处理
judge_position= [
[1, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1],
[1, 0, 0, 0, 0, 0, 2, 0, 0, -1, -1],
[0, 0, 1, 0, 0, 0, 2, 0, 0, -1, -1],
[0, 0, 1, 0, 0, 0, 0, 0, 2, -1, -1],
[0, 0, 0, 0, 1, 0, 0, 0, 2, -1, -1],
[1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2],
[1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0],
[1, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2]
]
position = randint(0,9)
if exp:
i = 0
for j in judge_position[position]:#调用上述列表
if j ==0:
expression.append(exp[i])
if i < len(exp):
i += 1
elif j ==1:
expression.append('(')
elif j ==2:
expression.append(')')
return expression
运行测试截图


功能3 限定题目数量,"精美"打印输出,避免重复
>f4 -c 3 1+2*(3+4)= 15 (1+2)*3+5= 14 ((1/2)-4)*5= 17.5
>f4 -c -200 题目数量必须是 正整数。 >f4 -c 3.5 题目数量必须是 正整数。 >f4 -c test 题目数量必须是 正整数。重难点1.如何规范化输出?
print('%-15s %-15s' % (expression, result)) # 规范输出格式
2.循环体
# 答案与题目横向对齐,使输出规范化,实现功能三
def normal(num):
i = 0
while i < num:
generate = Expression()
expression = generate.expre()
expression1 = make_Expression(expression) # 将中缀表达式转换为后缀表达式
result = make_Value(expression1) # 计算后缀表达式的值
expression=expression+"="
print('%-15s %-15s' % (expression, result)) # 规范输出格式
i += 1
3.如何与功能2区分?
在主函数中判断‘-c’是否在输入的命令行参数里,在则功能3,否则功能2.
4.如何在输入的命令行参数是负数或者小数时报错?
count=float(sys.argv[2]) # 获取生成题目的个数
if count >=1:
normal(count)
5.主函数
#定义主函数
def main(argv):
if '-c' in sys.argv: # 实现功能三
count=float(sys.argv[2]) # 获取生成题目的个数
if count >=1:
normal(count)
else:
print("题目数量必须是正整数。")
else:
question()#实现功能一二
#主函数
if __name__ == "__main__":
main(sys.argv[1:])
运行测试截图



总结
完成这个作业真的是花了很多功夫,因为自己的无知,很多时间都是在做无效的工作,但通过这次学习,我更加清楚了自己的弱势所在,更明白了该怎么去学习,谢谢前面人的工作,使我的学习有迹可循,在此特别感谢我的结对小伙伴梁梦瑶,能在我无比焦躁时安慰我的情绪,和我一起学习,一起努力。
