论文查重
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/ |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229 |
这个作业的目标 | 个人项目——论文查重 |
GitHub地址:https://github.com/Zhang1chen/3122004589.git
一.需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
二.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 80 |
Estimate | 估计这个任务需要多少时间 | 900 | 850 |
Development | 开发 | 350 | 400 |
Analysis | 需求分析 (包括学习新技术) | 40 | 25 |
Design Spec | 生成设计文档 | 30 | 20 |
Design Review | 设计复审 | 30 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 35 |
Design | 具体设计 | 60 | 40 |
Coding | 具体编码 | 60 | 70 |
Code Review | 代码复审 | 30 | 20 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 40 |
Reporting | 报告 | 40 | 20 |
Test Repor | 测试报告 | 50 | 50 |
Size Measurement | 计算工作量 | 20 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 20 |
合计 | 900 | 900 | 850 |
三、算法与接口设计
1.java.nio.file.Files
模块:java.nio.file
接口/类:Files
功能:提供了对文件和文件系统的访问,支持文件的读取、写入、删除等操作。
2.java.nio.file.Path
模块:java.nio.file
接口/类:Path
功能:表示文件系统中的路径,可以用于指定文件和目录的路径。
3.java.io.BufferedWriter
模块:java.io
接口/类:BufferedWriter
功能:用于高效地写入字符数据到文件中。
4. java.util.Set 和 java.util.HashSet
模块:java.util
接口/类:Set 和 HashSet
功能:Set 是一个不允许重复元素的集合接口,HashSet 是 Set 的一个实现类,基于哈希表。
5. java.lang.String
模块:java.lang
接口/类:String
功能:表示不可变的字符序列,支持字符串操作。
函数模块
di
运行结果
第一种输出的结果的查重率为78.95%。
第二种输出的结果的查重率为14.81%。
系统的计算模块主要包括以下几个核心类:
TextProcessor: 负责文本的处理和分词。
SimilarityChecker: 计算两个文本之间的相似度。
Main: 处理输入和输出,协调其他模块的工作。
1.2 类和函数设计
TextProcessor 类
职责: 处理文本数据,包括清理文本和分词。
主要函数:
tokenize(String text): 将输入的文本分词,并返回词汇集合。可能会用到正则表达式或分词库(如 jieba)来处理文本。
关键函数:
tokenize: 该函数负责将原始文本分解为词汇。它是文本处理的核心,需要保证分词的准确性,以便后续相似度计算的有效性。
流程图
SimilarityChecker 类
职责: 计算两个文本的相似度。
主要函数:
calculateSimilarity(Set
关键函数:
calculateSimilarity: 该函数计算两个集合的交集和并集,用于衡量文本相似度。它的核心在于准确计算交集和并集的大小,以便计算正确的相似度百分比。
流程图
Main 类
职责: 处理程序的入口点,包括文件读取、调用处理模块和结果输出。
主要函数:
main(String[] args): 处理命令行参数,读取文件,调用 TextProcessor 和 SimilarityChecker,并将结果写入输出文件。
关键函数:
main: 作为程序的入口点,负责整体流程控制。它负责将文件路径传递给 TextProcessor 和 SimilarityChecker,并处理文件输入输出。
流程图
改进思路
优化分词算法:
使用更高效的分词工具: 原始的分词方法可能效率低下,使用如 jieba 这样的高效分词工具可以显著提高分词速度和准确性。
避免重复分词: 确保每段文本只分词一次,将分词结果缓存起来。
优化集合操作:
使用高效的数据结构: HashSet 提供了常数时间复杂度的插入、删除和查找操作,相较于其他集合类型可以提高性能。
减少不必要的集合操作: 避免在计算交集和并集时进行多次集合操作。
减少冗余计算:
缓存中间结果: 在计算相似度时,缓存文本的分词结果,避免重复计算。
优化相似度计算逻辑: 确保相似度计算中交集和并集的计算是高效的。
单元测试
测试函数代码
`package com.example;
import org.junit.jupiter.api.Test;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SimilarityCheckerTest {
@Test
public void testCalculateSimilarity() {
SimilarityChecker checker = new SimilarityChecker();
Set<String> set1 = Set.of("hello", "world");
Set<String> set2 = Set.of("hello", "java");
double similarity = checker.calculateSimilarity(set1, set2);
assertEquals(50.0, similarity, 0.01, "Similarity calculation is incorrect.");
}
}
功能: 测试 SimilarityChecker 类的 calculateSimilarity 方法是否能正确计算文本相似度。 测试数据: wordsOriginal: Set.of("hello",'world') wordsPlagiarized: Set.of("hello", "java") 预期结果: 50.00%。这是计算出的相似度值。 思路: 通过计算交集和并集的比例来验证相似度计算的准确性。
package com.example;
import org.junit.jupiter.api.Test;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TextProcessorTest {
@Test
public void testTokenize() {
TextProcessor processor = new TextProcessor();
String input = "Hello, World!";
Set<String> result = processor.tokenize(input);
// 预期结果应为字符集合
Set<String> expected = Set.of("h", "e", "l", "o", ",", " ", "w", "r", "d", "!");
assertEquals(expected, result, "Tokenized words do not match expected results.");
}
}
`
TextProcessorTest.java:
测试函数: testTokenize()
功能: 测试 TextProcessor 类的 tokenize 方法是否能正确分词。
测试数据: 输入文本 "hello,world。"。
预期结果: Set.of("hello", "world")。这是分词后的预期结果。
思路: 通过手动分词和 TextProcessor 的输出进行比对,确保分词逻辑的正确性。
SimilarityCheckerTest.java:
测试函数: testCalculateSimilarity()
结果
项目总结
功能实现:
文本处理: 项目包含 TextProcessor 类来处理文本,将文本分解为字符集合。这个类提供了基本的分词功能,对于测试可以通过其 tokenize 方法来验证字符分割的正确性。
相似度计算: SimilarityChecker 类计算两个文本的相似度,采用的是基于字符集合的简单相似度计算方法(Jaccard相似度)。通过其 calculateSimilarity 方法,可以验证两个文本之间的相似度。
主程序: Main 类负责协调整个流程,包括读取文件、处理文本、计算相似度以及将结果输出到文件。通过 Main 的 main 方法,可以运行整个应用程序。
性能:
项目包含了对文件读取、文本处理和相似度计算的性能测量,能够帮助分析各个步骤的时间消耗。
测试:
单元测试: 使用JUnit对 TextProcessor 和 SimilarityChecker 类进行了单元测试,验证了文本处理和相似度计算的正确性。
集成测试: 通过 MainTest 类对主程序的整体流程进行了集成测试,包括文件创建、程序运行和结果验证。
不足之处
文本处理的局限性:
字符级分词: TextProcessor 的 tokenize 方法是基于字符的分词方法,这对英文或其他使用空格分隔单词的语言可能有效,但对于复杂语言(如中文),可能需要改进。
没有去除标点符号: 当前实现将标点符号也作为词汇处理,这可能不符合大多数文本处理的需求。
相似度计算方法简单:
没有考虑词频: 当前方法忽略了词频信息,只关注词汇集合的交集和并集。更精确的相似度计算可能需要引入词频或其他统计信息。
错误处理和日志记录:
错误处理: 主程序中只处理了 IOException,但可能还需要对其他潜在的错误(如非法文件路径、文件权限问题等)进行处理和报告。
日志记录: 项目中没有实现详细的日志记录,这对于调试和维护是很重要的。
测试覆盖率:
边界情况: 当前测试用例未覆盖所有可能的边界情况,如空文件、文件内容为空、相同内容的文件等。
异常情况: 测试用例中未涉及异常情况的处理,如文件读取失败、文件写入失败等。
性能考虑:大文件处理: 对于非常大的文件,当前的实现可能会遇到性能瓶颈或内存问题。可以考虑优化文件读取和处理的方式,如分块处理等。