python语言与系统设计 大作业——背单词的小软件

(一)需求和规格说明

问题描述:
这是一款帮助学生背单词的小软件。建立单词库:
第一个功能是学生帮助学生记单词,会显示单词库中单词的拼写、音标、词性、中文翻译,学生可以选择中途退出,再次进入的时候,可以从上次退出的位置继续,也可以重新开始,如果没有上一次的记录,则重头开始。
第二个功能是测试,有四种模式可以选择,一种是隐去单词部分字母,一种是给出中文然后默写单词,一种是给出单词选择对应的中文翻译,一种是给出翻译然后选择对应的单词。
第三个功能是增加单词,可以一个一个单词的增加,也可以读取文件增加。
第四个功能是删除单词,只能一个一个单词的删除。
第五个功能显示单词库中的所有单词。

编程任务:
(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、程序中只有删除单个单词的方法,没有删除一个词库的方法,我的预想是直接输入一个文件名,将文件中所有的单词删除(真正背英语单词的时候,要考虑词汇范围,过多的词汇会影响最后的学习成果),而一个一个单词的删除,仅仅是对应增加单个单词(我认为这两项功能并不实用)。

你可能感兴趣的:(学海无涯,python)