第一次个人编程作业
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34 |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229 |
| 这个作业的目标 | 独立实现论文查重算法 |
GitHub地址:https://github.com/windlessday
一、psp表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 40 |
| · Estimate | · 估计这个任务需要多少时间 | 15 | 20 |
| Development | 开发 | 220 | 240 |
| · Analysis | ·需求分析(包括学习新技 术) | 120 | 150 |
| · Design Spec | ·生成设计文档 | 30 | 10 |
| · Design Review | ·设计复审 | 30 | 20 |
| · Coding Standard | ·代码规范(为目前的开发 制定合适的规范) | 10 | 10 |
| · Design | ·具体设计 | 60 | 40 |
| · Coding | ·具体编码 | 60 | 40 |
| · Code Review | ·代码复审 | 50 | 40 |
| · Test | 测试(自我测试,修改 代码,提交修改) | 60 | 60 |
| Reporting | 报告 | 60 | 60 |
| · Test Repor | ·测试报告 | 30 | 30 |
| · Size Measurement | ·计算工作量 | 10 | 10 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
| · 合计 | 805 | 790 |
二、计算模块接口的设计与实现过程
代码组成
-
init:类的构造函数。用于初始化类变量,包括保存原始文本和待查重文本的内容及其分词结果。初始化后,类的实例会拥有两个主要属性:original_text 和 compare_text,以及它们的关键词列表 original_list 和 compare_list。
-
read_file:该函数负责读取文本文件的内容。具体而言,它从指定的文件路径读取原始文本和待查重文本,并将其分别存储在 original_text 和 compare_text 中。读取完成后,文本内容会保存在类的实例变量中,供后续处理使用。
-
long_text_preprocess:此函数负责对文本进行预处理。预处理包括去除文本中的标点符号,以保证分词的准确性。随后,使用 jieba.analyse.extract_tags 方法提取每篇文本中的前20个关键词,这些关键词将存储在 original_list 和 compare_list 中,作为后续相似度计算的基础。
-
text_checking:核心的查重函数。该函数首先调用 read_file 方法读取文本文件,然后调用 long_text_preprocess 方法对文本进行预处理。接着,构建两个文本的词频向量,并计算它们之间的余弦相似度。最终,将计算得到的相似度结果输出到指定的文件中,以便于进一步分析和记录。
类:Main:存放main函数和需调用的方法。
模块接口部分
| 类名 | 实现方法 |
|---|---|
| MainText(查重主程序类) | main方法 |
| MyException(异常处理类) | cast(异常抛出方法) |
| HammingUtils(海明距离模块工具类) | getHammingDistance(计算海明距离)、getSimilarity(输出相似度) |
| SimHashUtils(SimHash模块工具类) | getHash(计算哈希值)、getSimHash(计算simHash值) |
| TxtIOUtils(txt文件读写工具类) | readTxt(读取txt文本内容)、writeTxt(向txt文件输出文本) |

三、计算模块接口部分的性能改进
- 性能分析图
![]()
![]()
内存占用约300MB,主要用于储存字符串类(Byte[])。 - 最耗时的函数:分词函数
![]()
四、计算模块部分单元测试展示
- TxtIOUtilsTest测试
点击查看代码
package utils;
import CommonText.utils.TxtIOUtils;
import org.junit.Test;
public class TxtIOUtilsTest {
@Test
public void readNotTxtTest(){
String str = TxtIOUtils.readTxt("D:\\新建文件夹\\git\\pa\\src\\main\\java\\com\\will\\exception\\TooShortException.java");
System.out.println(str);
} //文件类型不是txt类型
@Test
public void readTxtTest() {
String str = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig.txt");
String[] strings = str.split(" ");
for (String string : strings) {
System.out.println(string);
}
} //路径存在,正常读取
@Test
public void writeTxtTest() {
TxtIOUtils.writeTxt("今天我好想你呀,好烦",
"F:\\DeskTop\\查重测试文件\\textWrite.txt");
} //路径存在,正常写入
@Test
public void readTxtFailTest() {
String str = TxtIOUtils.readTxt("D:/test/none.txt");
} //路径不存在,读取失败
@Test
public void writeTxtFailTest() {
TxtIOUtils.writeTxt("今天我好想你呀,好烦",
"D:/test/none.txt");
}
} //路径错误,写入失败

测试代码主要分成3部分
- 文件格式问题
- 文件路径问题
- 文件是否支持中文(UTF-8)的格式
- HammingUtilsTest测试
点击查看代码
package utils;
import CommonText.utils.HammingUtils;
import CommonText.utils.SimHashUtils;
import CommonText.utils.TxtIOUtils;
import org.junit.Test;
public class HammingUtilsTest {
@Test
public void getHammingDistanceTest() {
String str0 = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig.txt");
String str1 = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\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) + "%");
} //获取海明距离
@Test
public void getHammingDistanceFailTest() {
// 测试str0.length()!=str1.length()的情况
String str0 = "10101010";
String str1 = "1010101";
System.out.println(HammingUtils.getHammingDistance(str0, str1));
} //获取海明距离失败测试
@Test
public void getSimilarityTest() {
String str0 = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig.txt");
String str1 = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_add.txt");
int distance = HammingUtils.getHammingDistance(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
double similarity = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
System.out.println("str0和str1的汉明距离: " + distance);
System.out.println("str0和str1的相似度:" + similarity);
}
} //获取相似度测试

测试代码主要分成2部分
- 计算海明码距离
- 根据海明码距离获取两者相似度
- MainTest测试
点击查看代码
package MainText;
import CommonText.utils.HammingUtils;
import CommonText.utils.SimHashUtils;
import CommonText.utils.TxtIOUtils;
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class MainTest {
@Test
public void origAndAllTest() {
String[] str = new String[6];
str[0] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig.txt");
str[1] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_add.txt");
str[2] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_del.txt");
str[3] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_dis_1.txt");
str[4] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_dis_10.txt");
str[5] = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig_0.8_dis_15.txt");
String ansFileName = "F:\\DeskTop\\查重测试文件\\text.txt";
for (int i = 0; i <= 5; i++) {
Double similarity = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str[0]), SimHashUtils.getSimHash(str[i]));
String resultSimilarity = String.format("%.2f", similarity);
String result = "时间:" + DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss").format(LocalDateTime.now()) + "\n" + "原文件与文件" + i + "的相似度为:" + resultSimilarity + "\r\n";
TxtIOUtils.writeTxt(result, ansFileName);
System.out.println(result);
}
}
}

测试代码
- 将所给予的文件进行对比并给出相应的重复率
五、异常分析
TooExceptionTest异常分析
-
设计目标:为防止文本长度不满足要求而设置的规范长度异常
-
对应场景:当读取的文本内容少于300字符时将抛出。
点击查看代码
package CommonText.exception;
import CommonText.utils.SimHashUtils;
import org.junit.Test;
public class TooExceptionTest {
@Test
public void shortStringExceptionTest() {
//测试str.length()<300的情况
System.out.println(SimHashUtils.getSimHash("123123123"));
}
@Test
public void longStringExceptionTest() {
//测试str.length()>300的情况
String str = "俺是个不会大弧度看我等会哦亲我的环球网和决赛劳动法哈斯刘德华我的hi哦请问领导" +
"武器的hi去武汉我去饿的hi哦请问第一哦亲的去问我去饿逗我玩求交往i欧俄对其欧俄啊我当时哦啊的哈斯哦顶一哈我的要求我饿哦奥士第哦啊世界第哦啊五点一哦亲委员会i偶尔解耦2i二ui哦武器我赌气我额度去我额度去我饿u欧气端午i偶去我额度去我额度我穷恶uu为第哦啊五Iowa u欸哦请问u琼恩" +
"穷怕的机器我怕的机器我怕度假区我陪独家·1和我得回去我对况且我还对哦回去我的用户hi old擦拭哦撒野好滴哦亲五月底哦我企业的2二哈我soil的海外哦对后期我都会去我额度和3请问黑哦而囧决赛哦对哈死哦等哈我电话" +
"回去我会为我却我穷恶u为皇帝哦琼文读取我饿u穷第七位赔钱为多求求我额u奇偶我穷恶ui哦额i偶去我额度去我饿u去我额u请我i额u艾欧哦企鹅ui哦请问u去我饿u无穷而无穷而且我" +
"哦i稳压器我饿u请我i额";
System.out.println(SimHashUtils.getSimHash(str));
System.out.println(str.length());
}
}

TxtExceptionTest异常分析
点击查看代码
package CommonText.exception;
import CommonText.utils.TxtIOUtils;
import org.junit.Test;
public class TxtExceptionTest {
@Test
public void NotTxtExceptionTest() {
String str = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\text.java");
System.out.println(str);
}
@Test
public void IsTxtExceptionTest() {
String str = TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\test.txt");
System.out.println(str);
}
}




浙公网安备 33010602011771号