第一次个人编程作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class78-Grade2024-CS
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class78-Grade2024-CS/homework/15702
这个作业的目标 完成个人项目:论文查重

代码仓库: https://github.com/RettoST/Retto/

1.概述

  • 1.项目名称: 论文查重
  • 2.语言:python3
  • 3.运行方式
	python main.py <原文文件> <抄袭版文件> <结果文件>
  • 目标:给定原文文件和抄袭版论文文件,计算重复率,并将结果写入结果文件,保留两位小数

2. 需求分析

2.1 功能需求

  • 1.从命令行读取三个参数:原文路径、抄袭版路径、答案输出路径
  • 2.读取原文与抄袭文件内容
  • 3.计算文件重复率
  • 4.将重复率写入答案文件,保留两位小数
  • 5.异常处理(空文件、路径不存在等)

2.2 其他需求

  • 1.不能出现内存泄漏严重
  • 2.五秒内未给出答案
  • 3.占用的内存超过2048MB
  • 4.不能发生异常退出
  • 5.尝试连接网络、尝试读写其他文件或影响使用
  • 6.代码的可读性(注释),变量、函数、类命名的规范化

3. 总体设计分析

3.1 模块划分

计算模块
├── 文件读取
├── 文本预处理
├── 相似度计算
└── 结果输出

3.2 核心函数

函数名 所在文件 功能 输入 输出
read_file(path) src/plagiarism.py 读取文件内容 文件路径 文本字符串
normalize_text(text) src/plagiarism.py 去除空白字符 原始文本 规范化文本
calc_similarity(orig, plag) src/plagiarism.py 计算相似度 两段文本 浮点数0.00~1.00
main() main.py 调用计算模块

4. 核心算法

4.1 算法选择

本程序使用 Python 标准库 difflib.SequenceMatcher 计算相似度
对于大文本(超过5w字符)采用 n-gram + Jaccard 进行优化

SequenceMatcher 相似度公式:

similarity = 2 * M / (len(orig) + len(plag))

其中:

  • M:两段文本匹配的字符数;
  • len(orig):原文长度;
  • len(plag):抄袭版长度。

n-gram 就是连续的 n 个字符,以 n = 4 为例,对文本今天天气很好切分:

今天天气
天天气很
天气很好

每个片段就是一个 4-gram。
把所有 4-gram 收集起来,放进一个集合(自动去重)

Jaccard 算法相似度公式:

J(A, B) = |A ∩ B| / |A ∪ B|

其中:

  • A ∩ B :两个集合共有的碎片数量;

  • A ∪ B:两个集合合并后一共有多少种不同碎片;

  • 结果范围是 0 到 1。

4.2 算法流程

flowchart TD A[读取原文] --> B[读取抄袭版] B --> C[去除空白字符] C --> D[计算匹配字符数(对于大文本进行分词切分)] D --> E[计算相似度] E --> F[保留两位小数] F --> G[写入答案文件]

5. 异常处理设计

考虑到特殊编码导致的读取混乱的错误,只对常见编码进行读取(UTF-8与GBK),若无法读取则强制以UTF-8进行读取

在main中对参数进行异常处理,并对异常打印输出

6. 性能

1.测试用例

常规文本测试:常规文本的抄袭修改

古诗测试:涵盖原文与译文的测试

大文本测试:20w字的大幅测试

2.测试结果

常规文本与古诗测试均正常输出结果,时间极短
5f5967176ba3bd334b72b28d7c69772e

而大文本测试使用大约一分钟,需要优化

b22c69ff589068c90d572d86e668a064
即使是大文本的内存占用依旧很小,不考虑内存优化
81129a92fd5f053994e35344afcf068f

6.1 目标

  • 运行时间 < 5 秒
  • 内存占用 < 2048MB

6.2 性能瓶颈

观察对大文本查重的cProfile得到是 calc_similarity 中的计算相似度算法使用时间过高

6.3 优化思路

网上查找得知 difflib.SequenceMatcher 的时间复杂度是 O(n2)
查找到算法 n-gram 与 Jaccard 复杂度为 O(n)
短文本用 difflib 保证精度,长文本(5w)使用 n-gram + Jaccard,复杂度从 O(n2) 降到 O(n)
具体优化思路详见4.1算法选择

6.4 性能测试结果

由图可得满足了对大文本的时间优化
e5f1cb7529c11d00ee69235857fcaabf

7.测试

非常幽默的,官方测试用例的orig_0.8_del与全部的orig_0.8_dis部分全部都是以html发送的,并不是实际的文本内容,这样会导致相似度奇低无法正常测试,在源代码中已经对这部分纰漏进行修改并测试。
为了节省篇幅,不放出具体测试的截图:

测试文件 相似度 实际用时(ms)
orig_0.8_add.txt 0.91 172.939
orig_0.8_del.txt 0.87 175.8819
orig_0.8_dis_1.txt 0.97 78.9586
orig_0.8_dis_10.txt 0.81 115.2905
orig_0.8_dis_15.txt 0.58 155.4837

单元测试得到的测试覆盖率截图

图片
测试用例的编写主要是实际需求的测试,以及基本上完全地测试算法的所有情况(因为实际需求的编写问题,覆盖率好像不能正确计算)

测试部分花费特别特别多时间

附录

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 20
· Estimate · 估计这个任务需要多少时间 15 20
Development 开发 250 181
· Analysis · 需求分析 (包括学习新技术) 20 10
· Design Spec · 生成设计文档 30 30
· Design Review · 设计复审 20 8
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 20
· Design · 具体设计 30 32
· Coding · 具体编码 60 48
· Code Review · 代码复审 30 18
· Test · 测试(自我测试,修改代码,提交修改) 30 15
Reporting 报告 90 75
· Test Report · 测试报告 30 20
· Size Measurement · 计算工作量 30 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 105
合计 355 336
posted @ 2026-09-13 23:19  Retto  阅读(9)  评论(0)    收藏  举报