第一次个人编程作业

这个作业属于那个课程 个人项目
这个作业要求在哪里 作业要求
这个作业的目标 本次个人项目的目标是以“论文查重”为题,完整实践一次规范化的软件开发流程:使用Git进行代码管理并分阶段提交,通过代码质量与性能分析工具优化程序,设计单元测试用例并生成覆盖率报告,最终实现一个能在5秒内稳定输出重复率、具备异常处理能力的查重程序,并通过博客对开发过程进行总结,从而提升算法设计、代码规范、版本控制与测试评估的综合能力。

GitHob仓库链接:https://github.com/Akida1122-akd/3224004266

一、PSP 表格(预估 vs 实际)

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 20
· Estimate ·估计这个任务需要多长时间 15 20
Development 开发 120 200
· Analysis ·需求分析(包括学习新技术) 30 45
·Design Spec ·生成设计文档 20 20
·Design Reciew ·设计复审 10 10
·Coding Standard ·代码规范 10 15
·Design ·具体设计 20 30
·Coding ·具体编码 50 80
·Code Reviw ·代码复审 10 10
·Test ·测试(自我测试,修改代码,提交修改) 30 60
Reporting 报告 30 40
·Test Report ·测试报告 15 20
·Size Measurement ·计算功能工作量 10 10
·Postmortem &Process lmprovement Plan ·事后总结,并提出过程改进计划 15 20
合计 254 380

二、计算模块接口的设计与实现过程

1. 算法关键

本程序的核心算法使用 Python 内置的 difflib.SequenceMatcher。它基于最长公共子序列(LCS) 来计算两个字符串的相似度,计算公式为 2 * M / T(M 为匹配字符数,T 为总字符数)。相比于余弦相似度,这个算法对中文短文本的查重更加精准,并且完全不需要安装第三方依赖库。

2. 代码组织与函数关系

整个程序共有三个核心函数,它们之间的关系是“流水线”式的:

  • read_text(path: Path) -> str:负责读取文件。内部包含 try...except 异常防护,若文件不存在或编码错误,返回空字符串 ""。

  • plagiarism_rate(original: str, copy: str) -> float:负责查重计算。接收两个字符串,内部使用 SequenceMatcher 计算相似度,返回 0.0 到 1.0 之间的浮点数。

  • main() -> None:主入口。使用 argparse 解析命令行参数(原文、抄袭文、结果文件),依次调用上述两个函数,最后将结果格式化(保留两位小数)写入指定的 ans.txt 中。

3. 独到之处

在调用 SequenceMatcher 时,设置了 autojunk=False 参数。如果不设置,算法会自动忽略掉长文本中高频出现的字符(自动垃圾过滤),这会导致查重结果不准确。禁用该功能后,查重更加严谨。

image

三、计算模块接口部分的性能改进

1. 改进思路

最初我考虑使用“jieba 分词 + TF-IDF + 余弦相似度”的方案。但分析后发现,这需要引入第三方库,评测环境不一定支持,且计算量大。
后来我改为使用 Python 内置的 difflib.SequenceMatcher,不仅无需安装任何依赖,而且执行速度极快(毫秒级),完全满足评测要求的“5 秒内出结果”。

2. 性能分析

在终端运行 python -m cProfile -s cumtime main.py orig.txt orig_add.txt ans.txt 进行性能分析,结果如下:

  • SequenceMatcher 的 ratio() 函数是耗时最大的模块(通常占总耗时的 90% 以上),但整体耗时仍在 0.001s 级别。

  • 由于算法本身已足够快,无需进一步优化,只需保证在极端情况下(如超大文本)不超时即可。

屏幕截图 2026-09-12 220514

四、计算模块部分单元测试展示

1. 测试思路

在编码完成后,我使用 Python 内置的 unittest 框架设计了 12 个测试用例,采用白盒测试思路,覆盖了以下边界场景:

  • 完全相同(相似度应为 1.00)
  • 完全不同(相似度应为 0.00)
  • 部分抄袭(相似度应在 0.0 到 1.0 之间)
  • 原文为空、抄袭文为空、两者都为空
  • 纯空格或纯标点符号
  • 超长文本(测试性能稳定性)
  • 英文大小写区分
  • 特殊字符和换行符
  • 文件不存在(异常处理测试)
  • 读取文件发生异常(异常处理测试)

2. 测试结果

经过本地运行,所有 12 个测试用例全部通过(OK)。

屏幕截图 2026-09-12 220957

屏幕截图 2026-09-12 221049

屏幕截图 2026-09-12 221059

屏幕截图 2026-09-12 221105

五、计算模块部分异常处理说明

1. 异常设计目标

程序必须保证在评测过程中不发生异常退出。因此,在 read_text 函数中,我设计了 try...except 防护:
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8")
except (FileNotFoundError, UnicodeDecodeError):
return ""

  • 当输入文件路径不存在时(FileNotFoundError),返回空字符串。

  • 当文件编码不为 utf-8 时(UnicodeDecodeError),返回空字符串。

2. 单元测试例子

在测试用例 test_file_not_found 中,我传入了不存在的文件路径。程序没有崩溃,而是将 ans.txt 写入 0.00。这证明了异常处理逻辑的有效性。

屏幕截图 2026-09-12 221105

六、事后总结与过程改进

1. 实际耗时统计

结合 PSP 表格,本次作业实际耗时约 380 分钟,远超预估的 245 分钟。主要额外时间花在了调试 Python 环境(uv 环境的输出静默问题)以及配置 Git 远程推送网络异常上。

2. 过程改进计划

  • 环境方面:下次开发前应尽早确认 Python 虚拟环境是否能正常工作,避免在后期因环境干扰导致代码无法运行。

  • 版本控制方面:熟悉了 Git 的分支管理和远程推送流程。在遇到网络问题时,学会了使用 git push -u origin master:main --force 强制覆盖,确保代码能按时推送到云端。

  • 测试方面:掌握了 unittest 和 unittest.mock 的使用方法,能够模拟系统参数(sys.argv)来测试命令行工具,并能编写覆盖边界情况的测试用例,极大地提升了代码的健壮性。

posted @ 2026-09-12 22:18  Akida1122  阅读(38)  评论(0)    收藏  举报