第一次个人编程作业
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229 |
这个作业的目标 | 个人独立完成一次论文查重项目,学会使用PSP表格,完成性能分析以及测试 |
一、需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
二、PSP表
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 80 |
Estimate | 估计这个任务需要多少时间 | 740 | 750 |
Development | 开发 | 300 | 250 |
Analysis | 需求分析 (包括学习新技术) | 30 | 25 |
Design Spec | 生成设计文档 | 20 | 20 |
Design Review | 设计复审 | 20 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 35 |
Design | 具体设计 | 50 | 40 |
Coding | 具体编码 | 50 | 70 |
Code Review | 代码复审 | 20 | 20 |
Test | 测试(自我测试,修改代码,提交修改) | 50 | 40 |
Reporting | 报告 | 40 | 20 |
Test Repor | 测试报告 | 40 | 50 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 20 |
合计 | 740 | 750 |
三,项目依赖
项目构建工具:maven
单元测试:JUnit-4.12
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
实现思路
三、接口实现
3.1 读写txt文件模块
类:TxtIOUtils
方法:
readTxt:读取txt文件内容,返回String;
writeTxt:将数字写入到txt文件中。
3.2 计算SimHash模块
类:SimHashUtils
方法:
getHash:传入String,利用MD5计算出它的hash值,并以字符串形式输出;
getSimHash:传入String,计算出它的simHash值,并以字符串形式输出。
主要流程:
1.分词:使用了外部依赖汉语言处理hankcs包提供的接口,把需要判断的文本分词形成这个文章的特征单词;
List
2.获取hash值:通过hash算法把每个词变成hash值;
String keywordHash = getHash(keyword);
if (keywordHash.length() < 128) {
// hash值可能少于128位,在低位以0补齐
int dif = 128 - keywordHash.length();
for (int j = 0; j < dif; j++) {
keywordHash += "0";
}
}
3.加权、合并:通过 2步骤的hash生成结果,按照单词的权重形成加权数字串,把上面各个单词算出来的序列值累加,变成一个序列串;
for (int j = 0; j < v.length; j++) {
// 对keywordHash的每一位与'1'进行比较
if (keywordHash.charAt(j) == '1') {
//权重分10级,由词频从高到低,取权重10~0
v[j] += (10 - (i / (size/10)));
} else {
v[j] -= (10 - (i / (size/10)));
}
}
i++;
}
4.降维:把4步算出来的序列串变成 0 1 串,形成最终的simhash
String simHash = "";// 储存返回的simHash值
for (int j = 0; j < v.length; j++) {
// 从高位遍历到低位
if (v[j] <= 0) {
simHash += "0";
} else {
simHash += "1";
}
}
计算海明距离模块
类:HammingUtils
方法:
1.getHammingDistance:输入两个simHash值,计算它们的海明距离;
for (int i = 0; i < simHash1.length(); i++) {
// 每一位进行比较
if (simHash1.charAt(i) != simHash2.charAt(i)) {
distance++;
}
}
2.getSimilarity:输入两个simHash值,输出它们的相似度;
int distance = getHammingDistance(simHash1, simHash2);
// 通过海明距离计算出相似度,并返回
return 0.01 * (100 - distance * 100 / 128);
Main主模块
类:MainPaperChecker
主要流程:
调用TxtIOUtils,从命令行输入的绝对路径名读取对应的文件,将文件的内容转化为对应的字符串;
调用SimHashUtils,由字符串得出对应的 simHash值;
调用HammingUtils,由 simHash值求出相似度;
调用TxtIOUtils,把相似度写入最后的结果文件中。
四、性能分析
4.1 overview
4.2 方法调用情况
4.3 性能改进
由上图所展示的方法调用情况可知,程序主要消耗函数是外部依赖汉语言处理hankcs提供的接口,即分词模块,所以整体没有改进必要。
五、单元测试
5.1 读写txt文件模块测试
@Test
public void readTxtFailTest() {
// 路径不存在,读取失败
String str = TxtIOUtils.readTxt("D:/file/tests/o.txt");
}
@Test
public void writeTxtTest() {
// 路径存在,正常写入
double[] elem = {0.81, 0.45, 0.90, 0.22};
for (int i = 0; i < elem.length; i++) {
TxtIOUtils.writeTxt(elem[i], "D:/file/tests/ans.txt");
}
}
@Test
public void writeTxtFailTest() {
// 路径错误,写入失败
double[] elem = {0.81, 0.45, 0.90, 0.22};
for (int i = 0; i < elem.length; i++) {
TxtIOUtils.writeTxt(elem[i], "D:/file/t/a.txt");
}
}
测试结果:
代码覆盖率:
5.2 计算SimHash模块测试
public class SimHashUtilsTest {
@Test
public void getHashTest(){
String[] strings = {"美国", "51区", "雇员", "称", "内部", "有","9架","飞碟"};
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:/file/tests/org.txt");
String str1 = TxtIOUtils.readTxt("D:/file/tests/org_add.txt");
System.out.println(SimHashUtils.getSimHash(str0));
System.out.println(SimHashUtils.getSimHash(str1));
}
}
测试结果:
代码覆盖率:
5.4 Main主模块测试
public class MainTest {
@Test
public void origAndAllTest(){
String[] str = new String[6];
str[0] = TxtIOUtils.readTxt("D:/file/tests/org.txt");
str[1] = TxtIOUtils.readTxt("D:/file/tests/org_add.txt");
str[2] = TxtIOUtils.readTxt("D:/file/tests/org_add2.txt");
str[3] = TxtIOUtils.readTxt("D:/file/tests/org_del.txt");
str[4] = TxtIOUtils.readTxt("D:/file/tests/org_del2.txt");
str[5] = TxtIOUtils.readTxt("D:/file/tests/org_del3.txt");
String ansFileName = "D:/file/tests/ans.txt";
for(int i = 0; i <= 5; i++){
double ans = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str[0]), SimHashUtils.getSimHash(str[i]));
TxtIOUtils.writeTxt(ans, ansFileName);
}
}
}
测试结果:
结果文件:
六、异常处理
6.1 异常处理模块
类:ShortStringException
继承Exception类。
6.2 异常处理模块测试
public class ShortStringExceptionTest {
@Test
public void shortStringExceptionTest(){
//测试str.length()<200的情况
System.out.println(SimHashUtils.getSimHash("从前有座山"));
}
}
测试结果:
代码覆盖率:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步