文章目录
项目概述
这个项目属于哪个课程软件工程作业要求论文查重作业的目标学习使用PSP表格,学习commit规范参考文献《SimHash算法原理》、《查重算法》
0. Gitcode链接
git仓库地址
作业位于git仓库的master分支里的DuplicateCheckTest里
1.PSP表格
PSP2.1Personal Software Process Stages预估耗时(分钟)****实际耗时(分钟)Planning计划9090· Estimate· 估计这个任务需要多少时间4560Development开发120150· Analysis· 需求分析 (包括学习新技术)6060· Design Spec· 生成设计文档6060· Design Review· 设计复审6060· Coding Standard· 代码规范 (为目前的开发制定合适的规范)6060· Design· 具体设计6060· Coding· 具体编码3030· Code Review· 代码复审3030· Test· 测试(自我测试,修改代码,提交修改)180150Reporting报告6060· Test Repor· 测试报告6060· Size Measurement· 计算工作量1010· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划3030· 合计955970
2.题目描述
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
3.算法实现基本思路
3.1simHash算法原理
- 分词:现在有很多可供使用的包来进行文本的分词,本篇所使用的分词器是IKAnalysis,需要安装 IKAnalyzer2012_u6.jar包
- hash:通过hash函数计算各个特征向量(这里为划分好的词)的hash值,hash值为二进制数01组成的n-bit签名。
- 加权:权重:就是词频;把第2步生成的hash值从左至右与权重进行运算;如果该bit的数值为1,则将权重赋给该位;如果该bit的数值为0,则将权重的负值赋给该位。example:“我”,hash = 101011,weight(词频) = 5;则加权后的结果为:5 -5 5 -5 5 5;
- 合并:经过上述的三个步骤,我们可以得到全部词(word)的加权hash值,此时需要将全部的加权后的hash值进行累加;
- 降维:将第四步计算出来的序列串变为01串;具体规则:如果该位的数值>0,则置为1;反之则置为0.
- 海明距离(Hamming Distance):在信息编码中,两个合法代码对应位上编码不同的位数称为码距,又称海明距离;
3.2余弦定理查找相似度
(1)找出两篇文章的关键词;
(2)每篇文章各取出若干个关键词,合并成一个集合,计算每篇文章对于这个集合中的词的词频
(3)生成两篇文章各自的词频向量;
(4)计算两个向量的余弦相似度,值越大就表示越相似。
借鉴于:《SimHash算法原理》《查重算法》
4.模块接口部分
类名实现方法MainText(查重主程序类)main方法MyException(异常处理类)cast(异常抛出方法)HammingUtils(海明距离模块工具类)getHammingDistance(计算海明距离)、getSimilarity(输出相似度)SimHashUtils(SimHash模块工具类)getHash(计算哈希值)、getSimHash(计算simHash值)TxtIOUtils(txt文件读写工具类)readTxt(读取txt文本内容)、writeTxt(向txt文件输出文本)
5.执行结果
6.代码测试
6.1测试代码分析
6.1.1TxtIOUtilsTest测试
packageutils;importCommonText.utils.TxtIOUtils;importorg.junit.Test;publicclassTxtIOUtilsTest{@TestpublicvoidreadNotTxtTest(){String str =TxtIOUtils.readTxt("D:\\新建文件夹\\git\\pa\\src\\main\\java\\com\\will\\exception\\TooShortException.java");System.out.println(str);}//文件类型不是txt类型@TestpublicvoidreadTxtTest(){String str =TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\orig.txt");String[] strings = str.split(" ");for(String string : strings){System.out.println(string);}}//路径存在,正常读取@TestpublicvoidwriteTxtTest(){TxtIOUtils.writeTxt("今天我好想你呀,好烦","F:\\DeskTop\\查重测试文件\\textWrite.txt");}//路径存在,正常写入@TestpublicvoidreadTxtFailTest(){String str =TxtIOUtils.readTxt("D:/test/none.txt");}//路径不存在,读取失败@TestpublicvoidwriteTxtFailTest(){TxtIOUtils.writeTxt("今天我好想你呀,好烦","D:/test/none.txt");}}//路径错误,写入失败
测试代码主要分成3部分
- 文件格式问题
- 文件路径问题
- 文件是否支持中文(UTF-8)的格式
6.1.2HammingUtilsTest测试
packageutils;importCommonText.utils.HammingUtils;importCommonText.utils.SimHashUtils;importCommonText.utils.TxtIOUtils;importorg.junit.Test;publicclassHammingUtilsTest{@TestpublicvoidgetHammingDistanceTest(){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)+"%");}//获取海明距离@TestpublicvoidgetHammingDistanceFailTest(){// 测试str0.length()!=str1.length()的情况String str0 ="10101010";String str1 ="1010101";System.out.println(HammingUtils.getHammingDistance(str0, str1));}//获取海明距离失败测试@TestpublicvoidgetSimilarityTest(){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部分
- 计算海明码距离
- 根据海明码距离获取两者相似度
6.1.3MainTest测试
packageMainText;importCommonText.utils.HammingUtils;importCommonText.utils.SimHashUtils;importCommonText.utils.TxtIOUtils;importorg.junit.Test;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassMainTest{@TestpublicvoidorigAndAllTest(){String[] str =newString[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);}}}
测试代码
将所给予的文件进行对比并给出相应的重复率
6.2 异常分析
6.2.1 TooExceptionTest异常分析
设计目标:为防止文本长度不满足要求而设置的规范长度异常
对应场景:当读取的文本内容少于300字符时将抛出。
packageCommonText.exception;importCommonText.utils.SimHashUtils;importorg.junit.Test;publicclassTooExceptionTest{@TestpublicvoidshortStringExceptionTest(){//测试str.length()<300的情况System.out.println(SimHashUtils.getSimHash("123123123"));}@TestpublicvoidlongStringExceptionTest(){//测试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());}}
6.2.2TxtExceptionTest异常分析
packageCommonText.exception;importCommonText.utils.TxtIOUtils;importorg.junit.Test;publicclassTxtExceptionTest{@TestpublicvoidNotTxtExceptionTest(){String str =TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\text.java");System.out.println(str);}@TestpublicvoidIsTxtExceptionTest(){String str =TxtIOUtils.readTxt("F:\\DeskTop\\查重测试文件\\test.txt");System.out.println(str);}}
7.性能分析
7.1性能分析图
7.2方法调用情况
7.3 程序消耗最大函数
publicstaticStringgetSimHash(String str){//文本长度太短时HanLp无法取得关键字try{if(str.length()<300){TooException.cast();}}catch(TooException myException){
myException.printStackTrace();returnnull;}//用数组表示特征向量,取128位,从 0 1 2 位开始表示从高位到低位int[] v =newint[128];//1. 分词(使用了外部依赖hankcs包提供的接口)List<String> keywordList =HanLP.extractKeyword(str, str.length());int size = keywordList.size();int i =0;for(String keyword : keywordList){//2. 获取hash值String keywordHash =getHash(keyword);if(keywordHash.length()<128){int dif =128- keywordHash.length();for(int j =0; j < dif; j++){
keywordHash +="0";}}//3. 加权、合并for(int j =0; j < v.length; j++){if(keywordHash.charAt(j)=='1'){
v[j]+=(10-(i /(size /10)));}else{
v[j]-=(10-(i /(size /10)));}}
i++;}//4. 降维//储存返回的simHash值String simHash ="";for(int j =0; j < v.length; j++){if(v[j]<=0){
simHash +="0";}else{
simHash +="1";}}return simHash;}
版权归原作者 爱搬砖的小张 所有, 如有侵权,请联系我们删除。