第一次个人编程作业

GitHub仓库链接:https://github.com/onychen/gdut-software-engineering-2026

第一次个人编程作业:论文查重

姓名:陈锦清 学号:3124004049 班级:计科5班

开发时我用了 AI 辅助整理代码和文档。下面的测试和计时数据是我在本机运行得到的;PSP 用时按阶段回忆估算。

题目要求

程序从命令行接收三个绝对路径:原文、待检测文本和答案文件。它读取前两个文件,算出待检测文本相对原文的重复率,再把保留两位小数的结果写入答案文件。Python 入口是 main.py,运行不需要安装第三方库。

程序结构和算法

代码按职责拆成几个函数:main 处理命令行参数,run 负责串起读文件、计算和写答案;read_text_filewrite_rate_file 处理文件;normalize_text 负责文本规范化;similarity_rate 计算重复率;_gram_codes 生成用于比较的字符片段。

算法先统一全角字符和英文大小写,再忽略空格、标点和符号。随后把文本切成相邻的两个字符作为片段;短文本则按单个字符处理。程序统计原文中每种片段出现的次数,再从待检测文本逐个查找并消耗对应计数,避免候选文本反复使用同一段原文内容。计算公式是:

重复率 = 待检测文本中匹配到的片段数 / 待检测文本的片段总数

因此这是一个有方向的字符片段重合率,不是语义查重。词句换序、同义改写等情况可能识别不出来;清理规则和片段长度也会影响结果。

性能分析

如果把候选文本中的每个片段都逐一和原文比较,长文本会做很多重复工作,复杂度接近 O(N×M)。现在的做法是先为原文建立计数表,再扫描候选文本,时间复杂度为 O(N+M),空间复杂度为 O(U),其中 U 是原文中不同片段的数量。

我用 Python 自带的 cProfile 分析了合成文本:原文 380,000 字符、候选文本 403,000 字符,剖析耗时 0.902 秒。热点是二元组生成器(main.py 第28行),自身耗时 0.273 秒;similarity_rate 累计耗时 0.902 秒。

在 2,400 字符的样例上,计数表算法运行五次的中位数是 0.001588 秒;两两扫描原型的中位数是 0.24699 秒,前者约快 155.1 倍。具体时间会受运行环境影响。

image

image

单元测试和代码检查

测试代码在 tests/test_main.py,一共 23 个用例,包含这些情况:

测试内容 检查结果
文本相同、截取原文片段 重复率为 1.00
添加不相关内容、完全无关内容 检查比例变化和 0.00 边界
空原文、空候选、单字符文本 检查空值和短文本处理
标点、空白、全半角和大小写 检查规范化结果
候选重复片段超过原文次数 确认不会重复消耗原文片段
UTF-8 BOM、GB18030 检查文件编码读取
缺少文件、无效编码、答案路径不可写 检查异常提示和退出状态
命令行参数数量不正确 检查参数错误处理

运行 python -m unittest discover -s tests -v 后,23 个用例全部通过。Coverage 7.16.0 报告的总覆盖率为 99%,其中语句覆盖率 99%、分支覆盖率 93%;main.py 的语句和分支覆盖率都是 100%。

image

代码质量检查使用 Ruff 0.16.7,结果是 All checks passed!

异常处理

遇到输入文件不存在或不可读时,程序会指出文件路径并返回非零状态;文本既不是 UTF-8 也不是 GB18030 时会报解码错误;答案文件无法写入时会指出输出路径。参数数量不正确由 argparse 提示用法。原文或候选文本为空时,程序返回 0.00,不会因除数为零而异常退出。

对应的测试包括 test_missing_file_raises_clear_errortest_invalid_text_encoding_raises_clear_errortest_unwritable_answer_path_raises_clear_errortest_cli_requires_three_paths。这些用例分别检查文件缺失、编码错误、输出失败和参数错误。

运行示例

python main.py "C:\tests\orig.txt" "C:\tests\orig_add.txt" "C:\tests\ans.txt"

对题目说明中的示例文本,答案文件内容为 0.62。输出是 0 到 1 之间保留两位小数的比例。

PSP

PSP 预估总计 230 分钟,实际投入回忆估算为 43 分钟:需求 5 分钟、设计 7 分钟、实现和复核 7 分钟、测试 8 分钟、覆盖率与性能测量 8 分钟、报告整理 8 分钟。

总结

这次作业里,重复率的算法定义是比较关键的部分。标点怎么处理、重复片段是否能重复计数、分母取哪一边,都会改变结果。当前程序用字符二元组做局部匹配,速度比较快,但不能识别语义改写。以后可以再试不同片段长度,看看准确率和运行时间怎么变化。

posted @ 2026-09-13 22:35  oNyChEn123  阅读(8)  评论(0)    收藏  举报