软工作业2:个人项目
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229 |
这个作业的目标 | <完成个人项目:设计一个论文查重算法> |
Github链接
https://github.com/huangyanyi172/ruangong/tree/main/3222004767
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 370 | 420 |
Development | 开发 | 300 | 360 |
Analysis | 需求分析 (包括学习新技术) | 100 | 120 |
Design Spec | 生成设计文档 | 40 | 40 |
Design Review | 设计复审 | 20 | 20 |
Coding Standard | 需求分析 (包括学习新技术) | 30 | 40 |
Design | 具体设计 | 30 | 40 |
Coding | 具体编码 | 30 | 40 |
Code Review | 代码复审 | 20 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 40 | 40 |
Reporting | 报告 | 40 | 40 |
Test Repor | 测试报告 | 15 | 15 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 15 | 15 |
合计 | 400 | 450 |
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
SimHash算法
SimHash算法是一种局部敏感哈希算法,用于处理大规模数据的相似度计算问题。
-
1、文本分词和去停用词:首先对输入的文本进行分词处理,并去除停用词(如“的”、“是”等),以提取具有实际意义并且对文本内容有较强代表性的关键词。
-
2、特征权重计算:利用TF-IDF算法计算每个关键词的权重,以此衡量关键词在文本中的重要程度。
-
3、生成哈希向量:对每个关键词计算hash值,并根据关键词的权重对这些哈希值的每一位进行加权处理。
-
4、叠加生成最终哈希值:将所有关键词的加权hash值进行叠加,根据每位的正负决定最终hash值的位值。
-
5、降维处理:对于n-bit签名的累加结果,如果大于0则置1,否则置0,从而得到该语句的simhash值。
-
6、计算汉明距离:通过比较不同文本的SimHash值,计算汉明距离,即两个字符串对应位置的不同字符的数量,来判定文本间的相似度。
流程图
接口设计与实现
类名 | 实现方法 |
---|---|
HammingUtils类 | 计算海明距离并输出相似度 |
SimHashUtils类 | 计算哈希值、计算simHash值 |
TxtIOUtils类 | 读取txt文本内容并向txt文件输出文本 |
Main类 | 计算哈希值、计算simHash值 |
MainTest类 | 读取txt文本内容并向txt文件输出文本 |
性能分析
-
概览
-
实时内存
测试
- 单元测试展示
···
@Test
public void Test1(){
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str2 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_add.txt");
String str3 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_del.txt");
String str4 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_1.txt");
String str5 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_10.txt");
String str6 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_15.txt");
String ansFileName = "src/test/resources/test/test1.txt";
double ans1 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str1));
double ans2 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str2));
double ans3 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str3));
double ans4 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str4));
double ans5 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str5));
double ans6 = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str1), SimHashUtils.getSimHash(str6));
TxtIOUtil.writeTxt(ans1, ansFileName);
TxtIOUtil.writeTxt(ans2, ansFileName);
TxtIOUtil.writeTxt(ans3, ansFileName);
TxtIOUtil.writeTxt(ans4, ansFileName);
TxtIOUtil.writeTxt(ans5, ansFileName);
TxtIOUtil.writeTxt(ans6, ansFileName);
}
@Test
public void Test2(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String ansFileName = "src/test/resources/test/test2.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
@Test
public void Test3(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_add.txt");
String ansFileName = "src/test/resources/test/test3.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
@Test
public void Test4(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_del.txt");
String ansFileName = "src/test/resources/test/test4.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
@Test
public void Test5(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_1.txt");
String ansFileName = "src/test/resources/test/test5.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
@Test
public void Test6(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_10.txt");
String ansFileName = "src/test/resources/test/test6.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
@Test
public void Test7(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_15.txt");
String ansFileName = "src/test/resources/test/test7.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans,ansFileName);
}
··
-
测试覆盖率
-
测试结果
异常处理说明
- 文件不存在的异常测试:
···
/**
* 文件不存在异常测试
* @throws Exception
*/
@Test
public void Test8() throws Exception {
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.8_dis_.txt");
String ansFileName = "src/test/resources/test/test8.txt";
if(str0 == "" || str1 == ""){
throw new Exception("文件不存在");
}
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
···
- 文件为空的异常测试:
···
/**
* 文件为空异常测试
*/
@Test
public void Test9(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.1.txt");
String ansFileName = "src/test/resources/test/test9.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
···
- 文件字数太少的异常测试:
···
/**
* 文件字数太少异常测试
*/
@Test
public void Test10(){
String str0 = TxtIOUtil.readTxt("src/test/resources/test/orig.txt");
String str1 = TxtIOUtil.readTxt("src/test/resources/test/orig_0.2.txt");
String ansFileName = "src/test/resources/test/test10.txt";
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
TxtIOUtil.writeTxt(ans, ansFileName);
}
···
总结
-
在本项目中,我们完成了一个论文查重算法,用于检测原文与修改后的抄袭论文间的重复率,并将结果保存至指定文件。
-
算法的核心思想是对原文和抄袭版论文进行文本分词,并计算它们之间的相似度。我们使用了基于文本相似度的算法,通过比较原文和抄袭版论文中的词语、句子等元素,来判断它们之间的重复程度。
-
该算法通过命令行接收三个文件路径作为输入:原文、抄袭版和输出答案文件。核心基于文本相似度计算,对两篇论文进行分词并比较其相似度。
-
测试样例中,使用orig.txt作为原文文件,orig_add.txt等作为抄袭版文件,算法成功计算出各抄袭文件与原文的重复率,结果以浮点数形式精确到小数点后两位。
-
这个算法具有一定的实际应用价值,可以帮助人们发现论文抄袭行为,保护学术诚信。