这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade21-34/ |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade21-34/homework/13023 |
这个作业的目标 | 完成一个论文查重系统 |
github链接 | https://github.com/SoyoOfficial/SoyoOfficial |
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟 | 实际耗时(分钟 |
---|---|---|---|
Planning | 计划 | 60 | 60 |
· Estimate | · 估计这个任务需要多少时间 | 60 | 60 |
Development | 开发 | 1120 | 1290 |
· Analysis | · 需求分析 (包括学习新技术) | 300 | 360 |
· Design Spec | · 生成设计文档 | 70 | 60 |
· Design Review | · 设计复审 | 30 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 90 | 90 |
· Coding | · 具体编码 | 300 | 360 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 240 | 300 |
Reporting | 报告 | 240 | 250 |
· Test Repor | · 测试报告 | 60 | 70 |
· Size Measurement | · 计算工作量 | 60 | 60 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 120 | 120 |
· 合计 | 1420 | 1600 |
需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
类
- MainPaperCheck:main 方法所在的类
- HammingUtils:计算海明距离的类
- SimHashUtils:计算 SimHash 值的类
- TxtIOUtils:读写 txt 文件的工具类
- ShortStringException:处理文本内容过短的异常类
流程图
接口的设计和实现
读写txt文件的模块
类:TxtIOUtils
包含了两个静态方法:
1、readTxt:读取txt文件
2、writeTxt:写入txt文件
SimHash模块
类:SimHashUtils
包含了两个静态方法:
1、getHash:传入String,计算出它的hash值,并以字符串形式输出,(使用了MD5获得hash值)
2、getSimHash:传入String,计算出它的simHash值,并以字符串形式输出,(需要调用 getHash 方法)
海明距离模块
类:HammingUtils
包含了两个静态方法:
1、getHammingDistance:输入两个 simHash 值,计算出它们的海明距离 distance
2、getSimilarity:输入两个 simHash 值,调用 getHammingDistance 方法得出海明距离 distance,在由 distance 计算出相似度。
main主模块
main 方法的主要流程:
1.从命令行输入的路径名读取对应的文件,将文件的内容转化为对应的字符串
2.由字符串得出对应的 simHash值
3.由 simHash值求出相似度
4.把相似度写入最后的结果文件中
5.退出程序
性能分析
单元测试
public class TxtIOUtilsTest { @Test public void readTxtTest() { // 路径存在,正常读取 String str = TxtIOUtils.readTxt("D:/test/orig.txt"); String[] strings = str.split(" "); for (String string : strings) { System.out.println(string); } } @Test public void writeTxtTest() { // 路径存在,正常写入 double[] elem = {0.11, 0.22, 0.33, 0.44, 0.55}; for (int i = 0; i < elem.length; i++) { TxtIOUtils.writeTxt(elem[i], "D:/test/ans.txt"); } } @Test public void readTxtFailTest() { // 路径不存在,读取失败 String str = TxtIOUtils.readTxt("D:/test/none.txt"); } @Test public void writeTxtFailTest() { // 路径错误,写入失败 double[] elem = {0.11, 0.22, 0.33, 0.44, 0.55}; for (int i = 0; i < elem.length; i++) { TxtIOUtils.writeTxt(elem[i], "User:/test/ans.txt"); } } }
测试结果:
覆盖率:
public class SimHashUtilsTest { @Test public void getHashTest(){ String[] strings = {"余华", "是", "一位", "真正", "的", "作家"}; for (String string : strings) { String stringHash = SimHashUtils.getHash(string); System.out.println(stringHash.length()); System.out.println(stringHash); } } @Test public void getSimHashTest(){ String str0 = TxtIOUtils.readTxt("D:/test/orig.txt"); String str1 = TxtIOUtils.readTxt("D:/test/orig_0.8_add.txt"); System.out.println(SimHashUtils.getSimHash(str0)); System.out.println(SimHashUtils.getSimHash(str1)); } }
测试结果:
覆盖率:
public class HammingUtilsTest { @Test public void getHammingDistanceTest() { String str0 = TxtIOUtils.readTxt("D:/test/orig.txt"); String str1 = TxtIOUtils.readTxt("D:/test/orig_0.8_add.txt"); int distance = HammingUtils.getHammingDistance(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1)); System.out.println("海明距离:" + distance); System.out.println("相似度: " + (100 - distance * 100 / 128) + "%"); } }
测试结果:
覆盖率:
public class MainTest { @Test public void origAndAllTest(){ String[] str = new String[6]; str[0] = TxtIOUtils.readTxt("D:/test/orig.txt"); str[1] = TxtIOUtils.readTxt("D:/test/orig_0.8_add.txt"); str[2] = TxtIOUtils.readTxt("D:/test/orig_0.8_del.txt"); str[3] = TxtIOUtils.readTxt("D:/test/orig_0.8_dis_1.txt"); str[4] = TxtIOUtils.readTxt("D:/test/orig_0.8_dis_10.txt"); str[5] = TxtIOUtils.readTxt("D:/test/orig_0.8_dis_15.txt"); String ansFileName = "D:/test/ansAll.txt"; for(int i = 0; i <= 5; i++){ double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str[0]), SimHashUtils.getSimHash(str[i])); TxtIOUtils.writeTxt(ans, ansFileName); } } }
测试结果:
异常处理
当文本长度太短时,HanLp无法取得关键字,需要抛出异常。
try{ if(str.length() < 200) throw new ShortStringException("文本过短!"); }catch (ShortStringException e){ e.printStackTrace(); return null; }