第一次个人编程作业
https://github.com/uryyy16/Sensitive-words-detection
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 15 | 10 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 600 | 600 |
· Design Spec | · 生成设计文档 | 40 | 30 |
· Design Review | · 设计复审 | 60 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 10 |
· Design | · 具体设计 | 300 | 600 |
· Coding | · 具体编码 | 600 | 600 |
· Code Review | · 代码复审 | 60 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 280 | 120 |
Reporting | 报告 | ||
· Test Repor | · 测试报告 | 30 | 10 |
· Size Measurement | · 计算工作量 | 15 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
· 合计 | 2060 | 2080 |
二、计算模块接口
(3.1)计算模块接口的设计与实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。
对于敏感词的检测,主要从两个方面考虑:
- 一是一个敏感词可能以很多种形式出现,怎样在文本中正确找到所有形式。
- 二是怎样在待检测文本中快速找到这些敏感词的所有形式。
对于第二个方面,很自然地想到ac自动机。
主要考虑第一个方面:
-
中文敏感词可能进行一些伪装,在敏感词中插入除字母、数字、换行的若干字符仍属于敏感词。如:当山寨为敏感词词汇时,山_寨,山@寨,山 寨,均可视为敏感词。
解决方法:将这些字符全部替换成#,匹配时忽略#。不是直接将其去掉是因为这样会影响找到的敏感文本在文中的位置,导致输出时出错
-
中文文本中存在部分谐音替换、拼音替代、拼音首字母替代的敏感词(拼音不区分大小写),如 shan寨,栅寨,山Z等均可视为敏感词。
原先想法:将敏感词的所有形式和待检测文本都转换为拼音,Trie树上的每一个节点为一个字母。
问题:如果出现拼音为sha han的敏感词,待检测文本中出现shan就会匹配上,而实际上shan并不是敏感词。
解决方法:将拼音和英语字母都映射为数字,Trie树上的每个节点为一个数字。
-
中文文本中还存在少部分较难检测变形如繁体、拆分偏旁部首(只考虑左右结构)等。
解决方法:繁体和简体的拼音一致,在本质上也属于拼音替代的情况。对于拆分偏旁部首,我的做法是:建立字典1(key为可以被拆分的左右结构的汉字,value为拆分后的汉字)。在读入敏感词时,建立字典2(key为拆分后的汉字,value为合成的汉字),判断此时读入的汉字能否被拆分,如果可以被拆分,将其放入字典2,对文本进行处理时,如果遇到相邻两个汉字在字典2中能被找到,就将其替换成其对应的value,即其对应的合成汉字,再跑ac自动机进行匹配。
-
英文文本不区分大小写,在敏感词中插入若干空格、数字等其他符号(换行、字母除外),也属于敏感词,如hello为敏感词时,he_llo,h%ell@o,he llo均为敏感词 。多个敏感词之间不考虑嵌套出现的情况,但可能存在变形后插入字符的情况。
解决方法:将其全部转换为小写,用#替代这些字符。
代码中包括的文件、类、函数及其功能如下图所示:
流程图如下:
运行结果:
结果可视化:
(3.2)计算模块接口部分的性能改进。记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS 2019、JProfiler或者Jetbrains系列IDE自带的Profiler的性能分析工具自动生成),并展示你程序中消耗最大的函数。
用Pycharm中自带的Profiler的性能分析工具自动生成
按总时间排序:
按函数实际运行时间排序:
可以看到lazy_pinyin和pinyin花费了很多时间,但是不用pypinyin库我就无法轻松将汉字转换为拼音,所以暂时没能改进性能。
(3.3)计算模块部分单元测试展示。展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。
首先测试了:
-
读入敏感词函数
-
输出其已完成映射的所有可能形式的函数
-
读入待检测文本、将符号改为#并合并被拆开汉字的函数
再对整个项目进行测试:
测试了敏感词中间插入字符、英文大小写、用首字母代替、拼音代替、繁体字和偏旁部首拆分的情况
单元测试得到的测试覆盖率:
(3.4)计算模块部分异常处理说明。在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。
IOError:当文件路径错误或无法打开时提示错误
class MyTestCase(unittest.TestCase):
def test_something(self):
s = main.Sensitive_words()
try:
s.read_sensitive_words(file_words)
except IOError:
self.assertTrue(True) # add assertion here
else:
self.assertTrue(False)
三、心得
(4.1)在完成本次作业过程的心得体会
最大的心得体会应该是深刻理解了一个项目更重要的部分是前期的思路,设计和规划,而不是在编码本身。这次作业我花的大部分时间都在前期的思考,但是即使是这样,后面写代码的时候还是免不了有些地方要推翻重来。另外,速成了python,明白了python的一些基本语法和数据结构。