第一次个人编程作业

https://github.com/83675299/test1/tree/main/031902505

一、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 5 5
· Estimate · 估计这个任务需要多少时间 5 5
Development 开发 5 5
· Analysis · 需求分析 (包括学习新技术) 220 300
· Design Spec · 生成设计文档 5 5
· Design Review · 设计复审 5 5
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 30
· Design · 具体设计 30 120
· Coding · 具体编码 600 900
· Code Review · 代码复审 30 60
· Test · 测试(自我测试,修改代码,提交修改) 600 600
Reporting 报告 60 60
· Test Repor · 测试报告 10 30
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 30
· 合计 1635 2165

二、计算模块接口

2.1 计算模块接口的设计与实现过程

2.1.1 概述

本次作业实现的是敏感词过滤的功能,我在最开始没有查阅资料前,是想遍历解决,但这样效率太低了,于是就通过查阅资料,发现DFA算法是一个不错的解题算法,然后又和同学讨论发现AC自动机是DFA的升级版,效率更高,最后决定使用AC自动机作为主要算法。然后这次作业还需要很多其他细节功能,也花费了很大的力气,最后还是没能全部完成,左右偏旁拆字未实现,首字母拼接只实现了一部分,其余功能都完成了。

Node节点:

class Node(object):
    # value是该节点存的字,fail是指向的节点,next是子字典,word是目前建立的trie树
    def __init__(self, value=None):
        self.value = value
        self.fail = None
        self.next = dict()
        self.word = ''
        self.isend = False

2.1.2 项目设计结构

我设计了两个类和五个方法,类分为节点类和AC自动机类,方法分为文件读入,汉字转拼音,建树,实现fail指针和search搜索。先建树,然后在建树的基础上增加fail指针提升搜索效率,再通过AC自动机对文章进行搜索,这就是主要框架,其他的细节功能都加在了建树和搜索的方法里了。

2.1.3 AC自动机及search

AC自动机就是先通过给定的敏感词建立trie树,如下图:

再在trie树的的基础上增加fail指针,首字母的fail指针指向根节点,其他节点的fail指针是指向他父亲节点的fail指针指向的相同字母的子节点,像图中的'b'指向'b'。假如搜索的是abd,如果用DFA算法的话,在搜索ab后,发现'c'不是'd',就要对下一个字母重新搜索,而使用fail指针后,a的子节点b指向了root的子节点b,继续搜索就找到了d,这样效率会提高很多。

在search方法里先把读进来的字符串拆成字母或特殊字符,特殊字符就直接跳过;字母的话先变成小写,然后顺着trie树和fail指针搜索,看起来比较容易实现,但细节方面我经过多次修改,还是很费力气的。

2.1.4 汉字变成拼音等功能的实现

python里有个拼音的库,可以直接使用,树的每个节点就是用汉字拆成的字母来建成的,这样方便搜索。首字母的功能较难解决,如"fa lun gong","f l g"都是敏感词,那"gong"的两个g,在第一个g结束的话,后面"ong"就没有了,如果在第二个g结束的话,"f l g"就不能被识别出来,这两点我只能解决一点,还没有想到好的解决方法。最后文件读入和输出功能也走了一些弯路,用了不少时间,我采用的是python里的sys.argv[]。

2.2 计算模块接口部分的性能改进

2.2.1 用cprofile进行性能测试,如图所示

对性能影响较大的大部分都是pypinyin库,还有一部分是字典功能耗性能较大,要改进性能的话需要不使用pypinyin的库,而是通过汉字输入的原理来自己写功能,但会很麻烦,所以这次我没有选择改进。

2.2.2 耗时最大的函数

耗时最大的函数是search()函数,具体代码在git中,不在此占用篇幅了。

2.3 计算模块部分单元测试展示

def test4(self):
    words = ['比赛', '大龙', '上单', '分钟']
    org = ['在今天的比#$%%^赛中 RNG 1:3 LNG 告负,随着本场比,,,赛的落幕,',
           'RNG2021年LPL夏季赛的征程就此结束。']
    ac = AC(words)
    ac.search(org, r'C:\Users\hqk\Desktop\rgzy\answer1.txt')
    f1=read_file(r'C:\Users\hqk\Desktop\rgzy\answer1.txt')
    f2=read_file(r'C:\Users\hqk\Desktop\rgzy\answer2.txt')
    self.assertEqual(f1,f2)

测试了search()函数,看search()函数能否成功检测并输出敏感词检测结果。

这是单元测试的覆盖率。

与参考答案的对比,实在能力有限,还有40个解不来了,缺的应该是左右拆字和部分首字母。

2.4 计算模块部分异常处理说明

2.4.1 命令行参数读取

def test1(self):
    x = sys.argv[0]
    y= sys.argv[1]
    print(x+'\n'+y)

这个是我卡了好久的难题,可能本身这个读取参数并不难,但pycharm在哪里输入参数是个难点,我在python的控制台调试了半天都没弄好,最后在编辑配置里找到了输入参数的地方。

2.4.2 fail指针的使用

def test2(self):  
    root = tree_build(r'C:\Users\hqk\Desktop\rgzy\words.txt')
    root = ac_build(root)
    p = root
    p = p.fail
    if 'a' in p.next.keys():
        print('True')

在我写完这行代码后:

    p = p.fail

再打下这一行代码会报错:

if 'a' in p.next.keys():
        print('True')

这是因为在实现fail指针的最后需要写:

root.fail = root

如果不加这一句话的话,系统不知道root的fail指向哪,就会提示编译错误。

三丶心得

我之前有学习过python的语言,但没有实战过,这次实战接触了pychram这个工具,还使用了pypinyin等第三方库,发现python确实是一门方便的语言,也学习了Cprofiler的使用和单元测试。在完成此次的作业中,遇到的难题真的是一道又一道,一个小点可能都要啃好几个小时,还好有同是柯老板班的同学在,大家都不是大佬(我是最菜的),一起讨论,把这些难题几乎都解决了,这次的作业,对我的影响应该是巨大的吧,让我了解了很多之前都从来没有了解过的代码知识,期待下一次作业带给我的提升。

这是一个ans.txt生成的词云,大概就这样。

posted @ 2021-09-16 21:45  hqk111  阅读(54)  评论(0编辑  收藏  举报