软件工程第二次作业
软件工程第二次作业
github链接 | https://github.com/pigyoung661/pigyoung661/tree/main/3123004235 |
---|---|
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience |
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13477 |
这个作业的目标 | 设计一个论文查重程序,并进行性能分析与测试 |
一,PSP表
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 50 |
Development | 开发 | 200 | 320 |
· Analysis | · 需求分析(包括学习新技术) | 100 | 90 |
· Design Spec | · 生成设计文档 | 30 | 40 |
· Design Review | · 设计复审 | 30 | 40 |
· Coding Standard | · 代码规范(为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 40 | 60 |
· Coding | · 具体编码 | 60 | 90 |
· Code Review | · 代码复审 | 30 | 20 |
· Test | · 测试(自我测试,修改测试,提交修改) | 40 | 40 |
Reporting | 报告 | 50 | 70 |
· Test Report | · 测试报告 | 30 | 50 |
· Size Measurement | · 计算工作量 | 20 | 25 |
· Postmortem & Process improvement Plan | · 事后总结,并提出修改过程改进计划 | 20 | 20 |
合计 | 740 | 985 |
二,计算机模块接口的设计和实现过程
类函数构成:
- SimilarityCalculator.java(核心计算类)
- 核心函数:
calculateSimilarity()
:总入口,协调各模块计算最终相似度calculateSentenceSimilarity()
:句子级匹配主逻辑calculateTwoSentencesSimilarity()
:单个句子对的相似度计算normalizeWords()
:同义词标准化处理calculateLCSLength()
:最长公共子序列计算calculateWordFrequencySimilarity()
:词频辅助验证
- 核心函数:
- TextProcessor.java(文本处理工具类)
- 核心函数:
cleanText()
:文本清洗(去干扰字符、标点标准化)splitIntoSentences()
:按标点分割句子segmentSentence()
:句子分词(按字 / 词分割)getSynonymMap()
:提供同义词映射表getNoiseChars()
:提供干扰字符集合
- 核心函数:
- FileProcessor.java(文件操作类)
- 核心函数:
readFile()
:读取文件内容(UTF-8 编码)writeFile()
:写入结果到文件
- 核心函数:
- Main.java(程序入口类)
- 核心函数:
main()
:解析命令行参数,调用各模块完成流程
- 核心函数:
(1)具体运行流程图
(2)算法逻辑与总体设计
核心逻辑:采用 “句子级匹配为主、词频分析为辅” 的双层加权策略(句子相似度占 80%,词频相似度占 20%),既捕捉局部句子结构的相似性,又兼顾整体文本的词汇分布特征。
-
避免纯词频或纯哈希的局限性,同时适配 “整句抄袭修改” 和 “大段内容搬运” 等多种抄袭模式。
-
同义词动态映射:通过预设同义词库对文本进行标准化处理,将表层表述差异转化为统一语义特征,解决 “换词不换义” 的抄袭识别问题。
-
最长公共子序列(LCS)算法:针对句子内部结构,通过计算最长公共子序列长度与句子总长度的比值,量化句子结构的相似性,有效识别 “语序不变、局部修改” 的抄袭模式。
-
定向噪声过滤:通过预设干扰字符集合,精准移除无意义干扰项(如随机插入的特殊字符、冗余符号),还原文本核心内容,避免噪声对匹配结果的干扰。
-
全流程标准化:包含标点统一(全角 / 半角转换)、大小写归一化、停用词过滤等预处理步骤,确保不同格式的文本在同一基准上进行比对。
-
职责单一的类设计:将文件操作、文本预处理、核心计算分离为独立模块,降低耦合度,便于单独优化某一环节(如扩展同义词库、替换分词算法)。
-
阈值可调的判断逻辑:句子匹配阈值(默认 60%)、权重分配比例等参数可根据场景灵活调整,兼顾严格和宽松的查重需求。
三,计算模块接口的性能改进
1,耗时统计
句子级匹配粒度设计 | 30 | 以句子为单位而非字符级比对 |
---|---|---|
文本清洗前置处理 | 20 | cleanText 先过滤干扰再进入计算 |
算法逻辑分层实现 | 40 | 拆分句子匹配与词频计算为独立方法 |
边界条件提前判断 | 15 | 空文本直接返回 0.0 |
2,优化思路
- 采用句子级比对而非字符级或文档级,既避免了字符级比对的低效(O (n²) 复杂度),又比文档级整体比对更精准。这种粒度选择在设计阶段就平衡了效率与准确性,是性能优化的基础。
- 在
calculateSimilarity
入口先通过cleanText
完成干扰字符过滤、标点标准化,确保进入核心计算(如 LCS、词频分析)的文本已剔除噪声,减少无效计算(如对干扰字符的比对)。 - 将计算流程拆分为 “文本清洗→句子分割→句子匹配→词频分析→结果整合”,每个方法专注单一功能(如
calculateLCSLength
仅负责最长公共子序列计算)。这种设计减少了重复代码,便于缓存复用中间结果(如分词结果可在句子匹配和词频计算中共享)。 - 代码中对空文本、空句子列表等特殊情况做了提前判断(
if (origSentences.isEmpty() || plagSentences.isEmpty()) return 0.0
),避免无效的循环和计算,减少不必要的性能损耗。 - 核心采用 LCS 算法而非编辑距离,在句子级比对中 LCS 更关注 “相似部分的连续性”,计算步骤更简洁;同时用余弦相似度而非 Jaccard 系数计算词频,更适合处理词汇分布稀疏的文本场景。
3,性能分析图:
在这之中 calculateSentenceSimilarity是计算资源消耗最大的函数
四,计算模块部分单元测试展示
以下三个函数是需要重点验证的核心功能,直接影响相似度计算的准确性:
calculateTwoSentencesSimilarity(String s1, String s2)
- 功能:计算两个句子的基础相似度(基于同义词归一化和最长公共子序列 LCS)。
- 测试重点:验证同义词替换后 LCS 算法的准确性,确保语义相似的句子得到合理分数。
calculateWordFrequencySimilarity(String text1, String text2)
- 功能:通过词频向量的余弦相似度,衡量整体词汇分布的相似性。
- 测试重点:验证词频统计、向量构建及余弦公式的正确性,确保词汇重叠度与分数正相关。
calculateSimilarity(String orig, String plag)
- 功能:综合句子级相似度(70% 权重)和词频相似度(30% 权重),输出最终查重结果。
- 测试重点:验证权重计算逻辑,确保整体结果符合 “部分抄袭部分得分、完全抄袭得满分” 的预期。
部分测试函数代码:
testSplitIntoSentences
函数- 测试对象:
TextProcessor
类的splitIntoSentences
方法。 - 功能验证:该方法用于将一段文本按照中文的句号、感叹号、问号等标点符号分割成句子列表。测试用例中,输入包含不同标点的文本,期望分割后得到正确数量的句子,并且每个句子的内容符合预期;同时验证空文本输入时,返回空列表。
- 测试对象:
testSynonymReplacement
函数- 测试对象:
SimilarityCalculator
类的normalizeWords
方法。 - 功能验证:该方法用于将单词列表中的同义词替换为标准词汇。测试用例中,输入包含同义词的单词列表,期望替换后得到对应的标准词汇列表;同时验证输入非同义词的单词列表时,保持原词不变。
- 测试对象:
构建思路:
testSplitIntoSentences
数据构造- 正常文本场景:构造包含多种中文断句标点(句号、感叹号、问号)的文本,用于测试方法在常规文本分割时的准确性,确保能正确识别不同标点并分割出对应数量的句子。
- 边界场景:构造空文本,测试方法在输入为空时的处理逻辑,期望返回空列表,验证方法对异常输入的鲁棒性。
testSynonymReplacement
数据构造- 同义词场景:选取常见的中文同义词,如 “周天” 与 “星期天”、“马铃薯” 与 “土豆” 等,构造单词列表,测试同义词替换功能是否正常生效。
- 非同义词场景:选取没有同义词映射的单词,如 “测试”“代码”,构造单词列表,测试方法在遇到非同义词时是否能保持原词不变,确保方法不会错误替换非同义词。
五,计算模块部分异常处理说明
空文本输入异常
当用户输入空文本(如原文未填写、抄袭文为空白)时,
calculateSimilarity()
应返回 0.0
作为默认结果,避免因空指针或除以零等问题导致计算异常。