问题描述:
这是一款帮助学生背单词的小软件。建立单词库:
第一个功能是学生帮助学生记单词,会显示单词库中单词的拼写、音标、词性、中文翻译,学生可以选择中途退出,再次进入的时候,可以从上次退出的位置继续,也可以重新开始,如果没有上一次的记录,则重头开始。
第二个功能是测试,有四种模式可以选择,一种是隐去单词部分字母,一种是给出中文然后默写单词,一种是给出单词选择对应的中文翻译,一种是给出翻译然后选择对应的单词。
第三个功能是增加单词,可以一个一个单词的增加,也可以读取文件增加。
第四个功能是删除单词,只能一个一个单词的删除。
第五个功能显示单词库中的所有单词。
编程任务:
(1)建立单词库,并可以方便地对单词库进行增加、删除。
(2)随机读取一个单词,随机隐去单词中的一些字母,规则是:长度为2~4空一个字母,5~7空二个字母,8~10空三个字母,11以上空四个字母。用随机数方式确定隐去哪几个位上的字母,并在屏幕上显示带空格单词。
(3)用户填充空格处的字母,程序判断填充是否正确。
(4)当用户结束游戏时,统计正确率,并输出相应的鼓励语句。
(5)随机读取一个单词,给出音标、中文翻译、词性,默写出相应的单词。
(6)随机获得单词库中一个单词的翻译,再随机选择三个单词,将四个单词随机排列,从中选择翻译对应的单词。
(7)随机获得单词库中一个单词,再随机选择三个单词的翻译,将四个单词的翻译随机排列,从中选择正确的翻译。
(8)增加单词,有增加单个单词和读取文件两种方式,读取文件不需输入文件名,只要按照需求建立指定文件并按照固定格式存储即可。
(9)删除单词,只要输入需要删除单词即可,对于该单词的所有信息都会删除。
注:由于单词中空格不容易辨认,故将空格改为下划线。
1.设计思想
在本次大作业中,采用excel表存储数据,通过pandas.read_excel获取excel表中的数据中,存储在一个DataFrame中,后续所有的操作都在这个Data Frame中完成,最后在完成操作后,将内容写回读取的excel表。
一级菜单包含五部分:1.记单词或测试,2.增加单词,3.删除单词,4.显示所有单词,5.退出。在第一部分中,包含除返回外的四个功能,默写单词、填补单词、根据单词选翻译、根据翻译选单词。在增加单词部分,包含增加单个单词和读取文件增加单个单词,如果选择增加单个单词,则单词、音标、词性、翻译全部需要自己输入,如果选择以读取文件的方式增加单词,则需提前准备好相应的文件,运行时仅需选择相应功能即可。删除单词时仅有删除单个单词这一个功能,仅需输入该单词即可,相关的音标、词性和翻译会一次性删除。
2. 设计表示
函数:
数据类型 函数名称 描述
void My_menu() 显示主菜单,一级菜单
void Recite_words() 显示二级菜单1,对应主菜单的第一个选项,可以进行记单词和测试
void recite_words(num) 选择记单词的方式,如果输入为1,则从头开始记单词,如果输入为2,则从上次退出的地方继续记单词,如果没有之前的记录,则判定为从头开始,如果输入为其他数字,则由Recite_words()判定并反馈
void Stop_recite(num) 输入的数字是单词的编号,以此记录本次记单词退出的位置,内容将会写入文本文档中,如果下次需要继续,则直接调用文件中记录的内容
void write_word_from_memory(choice_num) 选择测试的功能后,如果输入为1,则隐去部分字母,需要补全字母,并统计正确率,如果输入为2,则给予提示(音标、词性、翻译),要默写出单词,如果输入为其他数字,则由Recite_words()判定并反馈
void judge_translate_from_word(choice_num) 选择测试的功能后,如果输入为3,则根据单词的翻译,从四个单词的选项中选择正确的单词,并统计正确率,如果输入为4,则根据单词,从四个翻译中选择与该单词对应的翻译,如果输入为其他数字,则由Recite_words()判定并反馈
boolean judge_in_words(string) 判断输入的字符串(单词)是否在单词库中,如果在则返回False,如果不在则返回True
DataFrame Add_words() 显示二级菜单2,对应主菜单的第二个选项,可以进行单词添加,可以选择单个单词或者读取excel文件的方式添加单词
void Show_all_words() 显示单词库中的所有单词,对应主菜单的第四个选项
DataFrame Delete_words() 显示二级菜单3,对应主菜单的第三个选项,可以进行单词删除,输入单词后,在单词库中寻找,没有找到则返回原来的dataframe,如果找到则返回删除单词后的dataframe
3. 核心算法
核心算法主要是在记单词和测试、添加单词和删除单词三个部分。
1、在记单词和测试部分:
在记单词部分,如果是从新开始,则直接设置在Dataframe中开始的位置为0,如果是从上一次继续,则读取文件中记录的数字,如果读取到了,则将遍历Dataframe的开始位置设置为读取到的数字,如果没有读取到,则同样设置开始位置为0,从头遍历。在没有遍历完Dataframe的情况下,会持续遍历Dataframe的数据,打印出其中所有的数据,在循环中,如果选择停止,则会记录停止的位置到相应的文件中,然后退出,如果选择继续,则会打印输出下一个单词的信息,如果输入不符合规范,则打印提示,需要重新输入。
在测试部分,如果选择隐去单词部分字母,先建立一个空列表(列表1),在列表长度小于dataframe的行数时,处于循环中,在循环内,先生成一个规定范围的随机数,规定范围是dataframe行号范围,如果随机数在之前生成的列表(列表1)中,则重新生成,如果不在,则将该随机数添加到列表(列表1)中,添加之后,首先获得随机数对应dataframe处的单词,获得单词的长度,根据规则获得需要隐去字母的数量,然后生成随机数,获得相应数量的的随机数,放置到新的列表(列表2)中,对新的列表(列表2)中的数据排序,根据列表(列表2)数据将单词中指定位置的字母替换成下划线并打印出,根据输入字母判断是否正确,统计并计算正确率,根据正确率输出鼓励的话。
如果选择默写单词,在将随机数添加到列表(列表1)中后,直接打印出dataframe该位置单词的词性、音标、中文翻译,然后根据输入的单词判断是否正确,计算正确率,输出鼓励的话。
如果选择根据翻译选单词,开始流程与前面相同,在将随机数添加到列表(列表1)中后,获得dataframe中该随机数处的单词和中文翻译,将单词添加到一个空列表(列表3)中,再从dataframe中随机选择单词,如果单词不在列表(列表3)中,则添加到其中,如果在,则重新选择,直到列表(列表3)中有4个单词,再次生成一个随机数,范围为(0,3),按照前面的方法,通过空列表(列表4)判定是否将列表中(列表3)对应位置单词输出出去,输出所有单词后,输出中文翻译,输入与之对应的单词,计算正确率并输出。
如果选择根据单词选翻译,核心算法与上述(根据翻译选单词)相同,仅选择获取的数据不同。
2、在添加单词部分:
如果选择添加单个单词,可直接设定dataframe中的值,依据现有dataframe的行数,再添加一行,如果选择读取文件添加单词,先生成该文件的dataframe,然后遍历,如果该文件的dataframe中的单词在原dataframe中没有,则直接用loc[]函数设定,如果原dataframe中有,则跳过,最后将修改过的dataframe重新写入原文件中。
3、在删除单词部分:
仅能一个一个单词的删除,先设定标志,如果在dataframe中没有找到要删除的单词,则输出提示并结束,如果找到该单词,则用drop()函数直接删除对应行,然后修改dataframe中后续单词的编号,然后将修改后的dataframe写入源文件中。
import random
import pandas as pd
#单词以编号,单词,读音,词性,中文翻译几部分组成
words = pd.read_excel("Words_Library.xlsx")
indexs = words['Number'].notnull()
words = words[indexs]
def Stop_recite(num):#停止背单词,并记录停止时的单词编号
file = open('Record.txt','r+')
file.truncate()
string = str(num)
file.write(string)
file.close()
print("停止完成")
def recite_words(num):#二级菜单功能1
if num == 1:
number = 0
else:
print("您将从退出的位置继续。")
file = open('Record.txt','r')
string = file.read()
if string == '':
print("没有记录,请从新开始")
number = 0
else:
number = int(string)
print("输入next显示下一个单词,输入stop停止")
print("单词的读音、词性和中文翻译:")
while number < len(words['Number']):
print(words['Word'][number],words['Phonetics'][number],words['Word_class'][number],words['Translate'][number])
recite_flag = input()
if recite_flag == 'stop':
Stop_recite(words['Number'][number]-1)
return
while recite_flag != 'next':
print("输入错误,请重新输入")
recite_flag = input()
number = number+1
print("词库结束。")
def write_word_from_memory(choice_num):
judge = []
right_number = 0
false_number = 0
while(len(judge)<len(words['Number'])):
ch = random.randint(0,len(words['Number'])-1)
if ch not in judge:
judge.append(ch)
if choice_num == 1:
string = words['Word'][ch]
word_len = len(string)
if word_len>10:
hide = 4
else:
hide = int((word_len-2)/3)+1
position = []
num = 0
while num<hide:
letter = random.randint(0,word_len-1)
if letter not in position:#获得要替换成下划线字母的位置,保证不取重复
position.append(letter)
num = num+1
true_letter = []
new_position = sorted(position)
#print(new_position)
ago_word = ''
split_word = []
for i in range(len(string)):
split_word.append(string[i])
for i in new_position:
true_letter.append(split_word[i])
split_word[i] = '_'
for i in split_word:
ago_word = ago_word+str(i)
#print(true_letter)
print("请填充空缺字母:"+ago_word)#字母间由空格分开
print(words['Phonetics'][ch]+'\n'+words['Word_class'][ch]+'\n'+words['Translate'][ch])
your_answer = input()
your_letter = your_answer.split()
if your_letter == true_letter:
right_number = right_number+1
else:
false_number = false_number+1
print("正确的答案是:"+words['Word'][ch])
else:#choice_num == 2
print(words['Phonetics'][ch]+'\n'+words['Word_class'][ch]+'\n'+words['Translate'][ch])
your_input = input("请输入单词")
if your_input == words['Word'][ch]:
right_number = right_number+1
else:
false_number = false_number+1
print("正确的答案是:"+words['Word'][ch])
sum_num = false_number+right_number
accuracy = right_number/sum_num
print("正确率为:"+str('{:.2%}'.format(accuracy)))
if accuracy >= 0.9:
print("你的正确率很高,请继续保持")
elif accuracy<0.9 and accuracy>=0.6:
print("你的成绩合格了,但仍有不足")
else:#accuracy<0.6
print("你没有取得合格的成绩,请努力学习")
def judge_translate_from_word(choice_num):
word_num = 0
right_number = 0
false_number = 0
judge = []
while word_num<len(words['Number']):
ch = random.randint(0,len(words['Number'])-1)
if ch not in judge:
judge.append(ch)
num = 0
if choice_num == 3:
string = words['Translate'][ch]
word_list = []
word_list.append(words['Word'][ch])
while num<3:
word_ch = random.randint(0,len(words['Number'])-1)
if words['Word'][word_ch] not in word_list:
num = num+1
word_list.append(words['Word'][word_ch])
print(string)
num = 0
choice_list = []
while num<4:
choice = random.randint(0,3)
if choice not in choice_list:
choice_list.append(choice)
num = num+1
print(word_list[choice])
true_word = input("请输入匹配的单词")
if true_word == words['Word'][ch]:
right_number = right_number+1
else:
false_number = false_number+1
else:
string = words['Word'][ch]
translate_list = []
translate_list.append(words['Translate'][ch])
while num<3:
translate_ch = random.randint(0,len(words['Number'])-1)
if words['Translate'][translate_ch] not in translate_list:
num = num+1
translate_list.append(words['Translate'][translate_ch])
print(string)
num = 1
choice_dict = {}
while num<5:
choice = random.randint(0,3)
if translate_list[choice] not in choice_dict.values():
choice_dict[num] = translate_list[choice]
print(str(num)+'、'+translate_list[choice])
num = num+1
#print(choice_dict)
true_word = input("请输入正确答案的选项")
if choice_dict[int(true_word)] == words['Translate'][ch]:
right_number = right_number+1
else:
false_number = false_number+1
word_num = word_num+1
sum_num = false_number+right_number
accuracy = right_number/sum_num
print("正确率为:"+str('{:.2%}'.format(accuracy)))
def Recite_words():#二级菜单
print("请选择功能")
options = ((1,'记单词'),(2,'测试'),(3,'返回'))
while(1):
for option in options:
print(option[0],option[1])
flag = input("选择功能:")
if flag == '1':
while(1):
next_options = ((1,'从新开始'),(2,'从退出的位置继续'),(3,'返回'))
for option in next_options:
print(option[0],option[1])
next_flag = input('请选择方式:')
if next_flag == '1'or next_flag == '2':
recite_words(int(next_flag))
elif next_flag == '3':
print("返回完成")
break
else:
print('输入错误,请重新输入')
elif flag == '2':#单词测试
third_options = ((1,'隐藏部分字母'),(2,'默写单词'),(3,'判断单词的翻译'),(4,'根据单词选择词义'),(5,'返回'))
for option in third_options:
print(option[0],option[1])
third_flag = input('请选择方式:')
if third_flag == '1' or third_flag == '2':
write_word_from_memory(int(third_flag))
elif third_flag == '3' or third_flag == '4':
judge_translate_from_word(int(third_flag))
elif third_flag == '5':
print("返回完成")
break
else:
print('输入错误,请重新输入')
elif flag == '3':
print("返回完成")
return
else:
print('输入错误,请重新输入')
def judge_in_words(string):
list1 = []
for i in range(len(words['Number'])):
list1.append(words['Word'][i])
if string not in list1:
return False
else:
return True
def Add_words():
print("选项菜单:")
options = ((1,'添加单个单词'),(2,'以文件的方式添加单词'),(3,'返回'))
while(1):
for option in options:
print(option[0],option[1])
flag = input("选择功能:")
number = len(words['Number'])+1
if flag == '1':
words.loc[len(words['Number'])] = [number,input("请输入单词:"),input("音标:"),input("词性:"),input("翻译:")]
words.to_excel("Words_Library.xlsx",index = False)#将改变后的单词库重新写入excel表中
elif flag == '2':
many_words = pd.read_excel("many_words.xlsx")
for i in range(len(many_words['Number'])):
if judge_in_words(many_words['Word'][i]) == False:
word_position = number-1
words.loc[word_position] = [number,many_words['Word'][i],many_words['Phonetics'][i],many_words['Word_class'][i],many_words['Translate'][i]]
number = number+1
words.to_excel("Words_Library.xlsx",index = False)
elif flag == '3':
print("返回完成")
return words.reset_index(drop = True)
else:
print('输入错误,请重新输入')
def Show_all_words():
new_words = words.reset_index(drop = True)
for i in range(len(new_words['Number'])):
print(new_words['Number'][i],new_words['Word'][i],new_words['Phonetics'][i],new_words['Word_class'][i],new_words['Translate'][i])
def Delete_words():
print("选项菜单:")
options = ((1,'删除单个单词'),(2,'返回'))
while(1):
for option in options:
print(option[0],option[1])
flag = input("选择功能:")
if flag == '1':
break
elif flag == '2':
print("返回完成")
return
else:
print('输入错误,请重新输入')
this_number = -1
old_len = len(words['Number'])
string = input("请输入要删除的单词:")
for i in range(old_len):
if string == words['Word'][i]:
this_number = i
break
if this_number == -1:
print("没有找到该单词")
return words
words.drop(index = this_number,inplace = True)
this_number = this_number+1
for i in range(this_number,old_len):#修改后续单词编号
words.loc[i] = [i,words['Word'][i],words['Phonetics'][i],words['Word_class'][i],words['Translate'][i]]
words.to_excel("Words_Library.xlsx",index = False)
return words.reset_index(drop = True)
def My_menu():
print("选项菜单:")
options = ((1,'记单词或测试'),(2,'增加单词'),(3,'删除单词'),(4,'显示所有单词'),(5,'退出'))
while(1):
for option in options:
print(option[0],option[1])
flag = input("选择功能:")
#print(flag)
if flag == '1':
Recite_words()
elif flag == '2':
words = Add_words()
elif flag == '3':
words = Delete_words()
elif flag == '4':
Show_all_words()
elif flag == '5':
print("退出完成")
break
else:
print("输入错误,请重新输入")
print("欢迎下次使用")
My_menu()
进一步改进:
1、大作业一开始准备以可视化界面的方式完成,但因为对于可视化界面的方法不熟,从时间方面考虑,最终没有采用该方法,而是选择在IDLE上显示。如果使用可视化界面,可以直接关联按钮和鼠标点击,大大节省输入的要求,如:在记单词中不用输入‘next’和‘stop’,直接建立两个按钮替代即可,在选择题的过程中,直接点按钮即可,不必输入,更符合选择题的做题习惯。
同时,可以使界面更简洁,不会有大量过去的信息留存在显示中,过多信息的留存,不符合一款记单词软件的要求(单词库的信息在测试时仍保留,不能很好地测试出学生的水平)。
2、在测试中3、4部分的选择题(4个单词中选与翻译匹配的,4个翻译中选与单词匹配的),仅完成了最基本的功能,对于输入的有要求,如:根据翻译选单词,必须输入完整的单词(如果选择没错,但拼写错误,会导致错误),没有对应的选项,在根据单词选翻译,因为中文翻译过长,所有选择了输入选项(数字)的方式完成,两种模式的输入方式没有统一。
我的想法有两个:第一种,直接与可视化相结合,不必考虑输入的规范,直接以按钮代替。第二种方式:修改成统一的输入要求,因为中文翻译过长,所以只能考虑输入选项(数字1234或字母ABCD),但我个人更倾向于第一种,所以在完成程序的编写,除了因为测试进行修改,没有统一格式。
3、记单词模式中,无论是在记单词的过程中退出,还是选择从退出的地方继续,都进行了读文件的操作,但是前提要求是文件必须存在,这就使得必须在使用程序前先建立好相应的文件,避免出现错误。
可以考虑python的os库,使用其中的方法,如果判定文件不存在,则直接建立文件,避免出错的可能性。
4、在以读取文件的方式添加单词时,可以使用append函数,但是经过测试,没有添加成功,最后采用遍历读取的文件,再将内容逐行写入dataframe中,然后再将dataframe的内容写入excel的方法,可以考虑采用append的方法,节省空间。还有,因为不需要输入(读取的文件名已设定好),所以在使用程序前,需要建立好对应文件(考虑输入文件名的方式修改,避免只能读取一个文件,减少程序外的操作)。
5、在添加单个单词的部分,对于输入内容没有限定,致使无论什么样的内容输入都可以通过,应该考虑添加判定内容,避免错误内容危害单词库。同时还有,对于添加内容没有判定同样的内容有没有在单词库中,应该添加判定:如果已经有该单词在库中,则添加失败。(英语中有动词做名词的用法,为了词性的区分,可以添加同样的单词,但对于输入内容的限定就成了问题)
6、单词库中缺少修改单词内容的功能,英语中有名词用作动词的用法,也有动词作为名词的用法,如果单词库中的中文翻译和词性不够全的话,只能通过删除后再添加的操作,应该再在一级菜单中添加一个修改单词的功能。(一个单词作为动词和名词的含义并不相同,还要考虑词性和翻译的对应功能,考虑直接修改数据形式,将词性一栏和翻译一栏融合,再添加修改单词功能,要修改整个程序中的各个地方,近乎重写程序了)
7、因为在程序中使用dataframe的方式存储读取的文件内容,为了消除warning和错误,使用了loc函数添加单词(直接设定dataframe的某一行为添加的内容),但又致使dataframe的标签修改,(如添加单词或删除单词后,直接显示单词库,会报错),所以需要reset_index重新确立dataframe中数据的标签,因为是在测试的过程中修改,可能有代码的冗余,需要重新审视自己的代码消除冗余。
8、程序中只有删除单个单词的方法,没有删除一个词库的方法,我的预想是直接输入一个文件名,将文件中所有的单词删除(真正背英语单词的时候,要考虑词汇范围,过多的词汇会影响最后的学习成果),而一个一个单词的删除,仅仅是对应增加单个单词(我认为这两项功能并不实用)。