GitHub链接
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 10 | 20 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 120 | |
· Design Spec | · 生成设计文档 | 30 | |
· Design Review | · 设计复审 | 5 | |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | ||
· Design | · 具体设计 | 180 | 300 |
· Coding | · 具体编码 | 900 | 1200 |
· Code Review | · 代码复审 | 600 | |
· Test | · 测试(自我测试,修改代码,提交修改) | ||
Reporting | 报告 | ||
· Test Repor | · 测试报告 | ||
· Size Measurement | · 计算工作量 | ||
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | ||
· 合计 | 1585 | 2475 |
二、计算模块接口
2.1 计算模块接口的设计与实现过程
2.1.1 程序设计思路
- 在刚开始看到这个题时我只能想到循环查找字符串、利用树存储来加快时间等模糊的想法,但并没有实际的能力去实现。在我参考了不少同学的思路后,我发现总共大多是使用DFA或AC自动机的方法。在思考哪个更适合我之后,我选择了用python来实现DFA算法。 如图将关键词“你真帅”“我真好”“你真牛”用该树存储起来。从根节点开始,在比较待查文本的字符时,若遇到“你”则进入“你”节点,并判断此时状态:显然并不是终点,“帅”或“牛”才是。而如果整个比较过程都没有出错,顺利到了终点,那么便成功找到了一个关键词,若出错则重来。
- 在python中,用字典dict来实现DFA算法较方便。如下,可见使用字典实现可以避免不少麻烦。
state_event_dict = {
'你':{
'真':{
'帅':{
'is_end':True
},'is_end':False
'牛':{
'is_end':True
},'is_end':False
},
},
'我':{
'真':{
'好':{
'is_end':True
},'is_end':False
},'is_end':False
}
},
2.1.2代码实现
-
类
-
内含class DFA
函数,自动生成keyword_list(关键词查找树),以及_generate_state_event_dict
函数,根据输入的关键词在(keyword_list)树上查找并输出。但只提供了基础的输入输出功能,对关键词输入的优化(增添删改)以及获取数据的输出格式还需外部函数进行优化。match
-
-
主要函数
- 将敏感词从文件输入并转为列表方便操作
-
将待查文本从文件输入转为字符串方便操作def read_keywords(file_path): with open(file_path, encoding='utf-8') as keyword_list: return keyword_list.read().splitlines()
-
将数据按格式输出到ans.txtdef read_article(file_path): with open(file_path, encoding='utf-8') as article: return article.read()
-
处理敏感字列表,加入拼音、拼音首字母、汉字、偏旁部首等各种变形的敏感字plusdef write_ans(file_path, ans_list): with open(file_path, 'w', encoding='utf-8') as ans: ans.write('total: '+str(ans_list[0])+'\n') for word in ans_list: if isinstance(word, int): continue ans.write('line'+str(word['line'])+': '+'<'+real_keyword[word['keyword']]+'> ' + word['match'] + '\n')
def word_handle(keyword_list): after_list = [] # 小写 for keyword in keyword_list: after_list.append(keyword.lower()) # 转拼音 for keyword in keyword_list: # 注意使用lazy_pinyin(一维列表)而不是pinyin(二维列表) # after_list.append("".join(lazy_pinyin(keyword))) pinyin_list = lazy_pinyin(keyword) # 首字母 first_letter_list = lazy_pinyin(keyword, 4) # 判断是否中文避免数组越界( if ord(keyword[0]) > 255: dfs(after_list, pinyin_list, first_letter_list, "", 0, len(keyword)) return after_list
- 关键的递归,让敏感字变形更迅速,扩充敏感字列表也就更方便
def dfs(after_list, pinyin_list, first_letter_list, cur_chars, w, length): if w == length: after_list.append(cur_chars) return dfs(after_list, pinyin_list, first_letter_list, cur_chars + first_letter_list[w], w + 1, length) dfs(after_list, pinyin_list, first_letter_list, cur_chars + pinyin_list[w], w + 1, length)
2.2 计算模块接口部分的性能改进
- 由于pycharm是社区版没有profiler,于是只好用了自带的cprofile,由图可见第三方库的引用占了不少的时间
2.3 计算模块部分单元测试展示
敏感词1
待查文本1
答案1
2.4 计算模块部分异常处理说明
三、心得
- 在写代码前一定要预留出足够的时间去思考需要完成什么、需要学什么、怎么调试,并且题目一定一定一定要看清楚,不然可能会出现急头白脸看了一堆资料、写了一堆东西结果没用的情况。
- 而本次实验对我来说比较难,参考了好多教程、代码,用了好多不同的方式才勉强出来一部分。但是即便花了不少精力,还是没能来得及,反思了下,原因应该是没有客观合理地预料这一周需要完成的各种事务,以至于没能预留出足够的时间在这个项目上,导致哪怕快通宵了还是没能完成。不过这才是第一次,希望吸取了经验教训后将来能有所进步。