这个作业属于哪个课程 | 班级的链接 |
---|---|
这个作业要求在哪里 | 作业要求的链接 |
这个作业的目标 | 实现论文查重算法,并对代码进行性能分析、单元测试,使用PSP表 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 200 | 220 |
Development | 开发 | 300 | 400 |
· Analysis | · 需求分析 (包括学习新技术) | 50 | 60 |
· Design Spec | · 生成设计文档 | 50 | 60 |
· Design Review | · 设计复审 | 50 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 50 | 30 |
· Design | · 具体设计 | 30 | 30 |
· Coding | · 具体编码 | 30 | 35 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 20 |
Reporting | 报告 | 30 | 30 |
· Test Repor | · 测试报告 | 30 | 30 |
· Size Measurement | · 计算工作量 | 60 | 50 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
· 合计 | 1000 | 1125 |
- 题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
- 计算模块接口的设计与实现过程
Python 的 difflib 库中的查重算法主要基于一个称为“gestalt pattern matching”的算法。通过最长连续匹配子序列,递归应用,垃圾元素处理,自动垃圾处理启发式等关键算法实现。
在本代码中,利用sys接口接收命令行参数,打开对应文件后,利用difflib库中的SequenceMatcher()接口进行论文查重匹配。再由ratio接口得到相似度。
流程图如上图。先加载文件的内容在调用difflib库中的查重算法(查重算法主要是基于序列比较的算法,它可以用来发现两个序列(例如字符串或列表)之间的相似之处)进行计算,最后输出结果到目标文件中。本代码中主要利用SequenceMatcher类进行匹配。
项目结构如上
已经过编译器自带的Code Quality Analysis工具的分析并消除所有的警告
- 性能分析
Pycharm自带的profier工具如图。
消耗最大的函数是find longest_ match(),这个是调用difflib库方法时,查重算法的核心,故消耗的时间也是最多的。
性能改进思路:利用生成器,多线程与多进程,异步编程,或者直接使用C/C++编写核心模块等等方法去改进性能
-
单元测试
对于输入的路径参数出错的情况进行处理
测试路径为空的情况
def test_read_empty_file(self): path_1="" path_2="" path_3="" c = main.Cnki(path_1, path_2, path_3) c.cnki()
测试路径不存在的情况
def test_non_exist_file(self): path_1 = "C:Users/mumao/Desktop/neloneli/neloneli/3122004444/orig.txt" path_2 = "C:Users/mumao/Desktop/neloneli/neloneli/3122004444/orig_1.txt" path_3 = "C:Users/mumao/Desktop/neloneli/neloneli/3122004444/orig_2.txt" c = main.Cnki(path_1, path_2, path_3) c.cnki()
测试结果
可见对于异常的命令行参数输入能弹出错误信息 -
覆盖率
-
异常
def jud_inp(self):
try:
with open(f'{self.file_ori}', 'r', encoding='utf-8') as file_original:
self.paper_orin_content = file_original.read()
with open(f'{self.filen_pla}', 'r', encoding='utf-8') as file_plagiarize:
self.paper_plag_content = file_plagiarize.read()
except FileNotFoundError:
print("请输入正确的文件路径")
return FileNotFoundError
def cnki(self):
if(self.jud_inp()==FileNotFoundError):
return FileNotFoundError
# 根据命令行第二个和第三个参数得到目标的原文件和抄袭文件
matcher = difflib.SequenceMatcher(None, self.paper_orin_content, self.paper_plag_content)
# 对两个文件进行查重,将结果放入目标文件中
similarity_ratio = matcher.ratio()
try:
with open(f'{self.file_res}', 'a', encoding='utf-8') as file_anwser:
file_anwser.write(format(similarity_ratio, '2f')+'\n')
except FileNotFoundError:
print("请输入正确的文件路径")
return FileNotFoundError
上述异常的错误对应场景均为命令行路径参数输入不当
- 总结
本次论文查重项目,学习到了测试,git,覆盖率,性能分析方法等等知识,收获很多