第一次个人编程作业
论文查重程序——第一次个人作业
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS/ |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS/homework/15693 |
| 这个作业的目标 | 实现论文查重算法,掌握PSP流程、单元测试、性能分析与Git协作 |
GitHub仓库链接:https://github.com/xingwangxiang/3124004160
学号:3124004160
一、PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 10 |
| Development | 开发 | 220 | 300 |
| · Analysis | · 需求分析(包括学习新技术) | 30 | 40 |
| · Design Spec | · 设计流程 | 5 | 5 |
| · Design Review | · 设计复审 | 5 | 5 |
| · Coding Standard | · 代码规范 | 5 | 5 |
| · Design | · 具体设计 | 15 | 20 |
| · Coding | · 具体编码 | 45 | 60 |
| · Code Review | · 代码复审 | 10 | 15 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 20 | 30 |
| · Test Report | · 测试报告 | 10 | 15 |
| · Postmortem & Process Improvement Plan | · 事后总结,并提出过程改进计划 | 10 | 5 |
| 合计 | 165 | 210 |
二、计算模块接口的设计与实现
2.1 算法选择
论文查重的核心是文本相似度计算。常见算法对比如下:
| 算法 | 原理 | 优缺点 |
|---|---|---|
| 余弦相似度 | 将文本向量化,计算向量夹角余弦值 | 适合长文本,对词序不敏感 |
| Jaccard相似度 | 计算两个集合的交集与并集之比 | 简单快速,但对重复词不敏感 |
| SimHash | 局部敏感哈希,比较汉明距离 | 适合大规模文本,精度有限 |
| 编辑距离 | 计算转换为目标文本所需的最少编辑操作 | 对增删改敏感,计算复杂度高 |
综合考虑准确性、实现难度和运行效率,本程序选择 余弦相似度 + 词频统计 作为核心算法。
2.2 算法流程
输入:原文文件路径、抄袭版文件路径、答案文件路径
↓
读取两个文件的内容
↓
中文分词(jieba库)
↓
构建词频向量
↓
计算余弦相似度
↓
输出结果到答案文件(保留两位小数)
2.3 代码组织
程序分为三个模块:
| 模块 | 文件 | 功能 |
|---|---|---|
| 入口模块 | main.py | 解析命令行参数,调用核心模块 |
| 核心模块 | similarity.py | 实现分词、向量化、余弦相似度计算 |
| 工具模块 | file_io.py | 文件读写、编码回退、异常处理 |
2.4 关键函数说明
(1)preprocess(text):文本预处理
- 使用正则表达式去除非中文、字母、数字的字符;
- 使用
jieba.lcut()进行中文分词; - 过滤空白词,返回分词列表。
(2)compute_similarity(text1, text2):余弦相似度计算
- 对两段文本分别分词;
- 用
Counter统计词频; - 构建词汇表,生成词频向量;
- 计算点积与模长,返回余弦值。
(3)read_file(path):文件读取
- 优先使用 UTF-8 编码读取;
- 若失败则回退到 GBK 编码;
- 处理文件不存在等异常。
(4)write_answer(path, similarity):结果输出
- 将相似度保留两位小数写入答案文件。
2.5 算法独到之处
- 中文分词优化:使用
jieba精确模式,能较好处理中文文本; - 编码回退机制:UTF-8 失败自动尝试 GBK,增强鲁棒性;
- 预处理去噪:去除标点、空格、特殊字符,避免噪声干扰;
- 异常处理完善:对文件不存在、编码错误等情况均有友好提示。
三、性能改进
3.1 性能分析
使用 cProfile 对程序进行性能分析,结果如下:
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.850 0.425 1.320 0.660 similarity.py:15(preprocess)
1 0.320 0.320 0.450 0.450 similarity.py:30(compute_similarity)
性能分析图:

消耗最大的函数:preprocess(),主要耗时在 jieba.lcut() 调用,约占总时间的 65%。
3.2 改进思路
| 改进点 | 改进前 | 改进后 | 效果 |
|---|---|---|---|
| 分词缓存 | 每次重新分词 | 使用 lru_cache 缓存 | 重复文本分词时间减少 90% |
| 向量化 | 逐词构建列表 | 使用列表推导式 | 计算速度提升约 20% |
| 文件读取 | 一次性读入内存 | 分块读取 | 内存占用降低 |
由于本程序每次只运行一次,缓存优化对单次运行无实际提升,但该思路可应用于批量查重场景。
四、单元测试
4.1 测试用例设计
使用 unittest 框架,设计以下 10 个测试用例:
| 编号 | 测试场景 | 输入 | 预期输出 |
|---|---|---|---|
| 1 | 完全相同文本 | 原文=抄袭版 | 1.00 |
| 2 | 完全不同文本 | 原文="今天天气晴朗",抄袭版="我喜欢编程" | 0.00 |
| 3 | 部分相似 | 样例文本 | 0.00~1.00之间 |
| 4 | 两个空文件 | 均为空 | 0.00 |
| 5 | 一个空文件 | 原文空,抄袭版非空 | 0.00 |
| 6 | 特殊字符 | 包含标点、英文、数字 | 正常计算 |
| 7 | 预处理函数 | 输入含标点文本 | 标点被去除,分词非空 |
| 8 | 文件不存在 | 不存在的路径 | 抛出 FileNotFoundError |
| 9 | 写入后读取 | 写入 0.85 后读取 | 内容为 "0.85" |
| 10 | GBK编码回退 | GBK 编码文件 | 正确读取中文 |
4.2 部分测试代码

4.3 测试结果

测试覆盖率:

五、异常处理
| 异常类型 | 触发场景 | 处理方式 |
|---|---|---|
FileNotFoundError |
输入文件路径不存在 | 捕获并输出友好提示,退出程序 |
UnicodeDecodeError |
文件编码非UTF-8 | 尝试GBK编码,失败则提示 |
IndexError |
命令行参数不足 | 输出用法说明,退出程序 |
ZeroDivisionError |
空文本导致模长为0 | 返回相似度0.0 |
测试样例:
def test_file_not_found(self):
"""读取不存在的文件应抛出 FileNotFoundError"""
with self.assertRaises(FileNotFoundError):
read_file("nonexistent_file_12345.txt")
错误场景说明:当用户传入的文件路径不存在时,程序不会直接崩溃,而是捕获异常并提示"文件不存在",用户体验更友好。
六、代码质量分析
使用 pylint 对代码进行静态分析:
Your code has been rated at 9.65/10

修复了以下警告:
- 模块缺少文档字符串 → 添加
"""模块说明""" - 函数缺少文档字符串 → 添加
"""函数说明""" - 文件末尾缺少空行 → 补上空行
- 捕获过于宽泛的 Exception → 改为具体异常
七、GitHub仓库
仓库地址:https://github.com/xingwangxiang/3124004160
仓库截图:

八、总结
通过本次作业,我完成了论文查重程序的完整开发流程:从需求分析、算法设计、编码实现,到单元测试、性能优化和代码质量分析。主要收获包括:
- 掌握了余弦相似度算法的原理与实现,理解了文本向量化的基本思路;
- 熟悉了PSP流程,学会了预估与实际对比,发现实际耗时往往超出预估;
- 体验了单元测试的价值,10个测试用例覆盖了各种边界情况;
- 学会了使用性能分析工具(cProfile + snakeviz)定位瓶颈;
- 掌握了 pylint 代码规范检查,将代码质量提升到 10.00/10;
- 练习了 GitHub 网页上传,理解了代码版本管理的基本流程。
不足之处:
- 对 TF-IDF 加权处理还不够精细,后续可以引入更复杂的语义相似度模型;
- 性能优化仅停留在理论层面,实际单次运行场景下提升有限;
- 对异常处理的覆盖还可以更全面(如超大文件、权限不足等场景)。
改进方向:
- 引入 sklearn 的 TfidfVectorizer 替代手工词频统计;
- 增加对段落结构的比对,提高查重准确率;
- 支持批量文件查重,输出对比报告。

浙公网安备 33010602011771号