个人项目作业-论文查重

该作业是广工2023软件工程课程的一部分,要求开发一个基于Java的论文查重系统。系统使用SimHash算法计算原文和抄袭版论文的相似度,通过计算海明距离来确定重复率。开发环境包括IntellijIDEA和JProfiler,依赖于HankCS的汉语言处理包。项目实现了读写TXT文件、SimHash计算、海明距离计算等功能,并进行了详细的单元测试以确保代码质量。
摘要由CSDN通过智能技术生成

这个作业属于哪个课程

广工2023软件工程课程

这个作业要求在哪里

个人项目作业-论文查重

这个作业的目标

1.PSP表格

2.编码

3.单元测试

4.性能测试

其他参考文献

CSDN

一、作业地址

gitcode地址

二、整体设计

2.1 需求分析

设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。

要求输入输出采用文件输入输出,规范如下:

  • 从命令行参数给出:论文原文的文件的绝对路径。

  • 从命令行参数给出:抄袭版论文的文件的绝对路径。

  • 从命令行参数给出:输出的答案文件的绝对路径。

注意:答案文件中输出的答案为浮点型,精确到小数点后两位

2.2 开发环境

  • 开发语言:Java 17

  • 开发工具:Intellij IDEA 2021

2.3项目依赖

  • 项目构建工具:maven

  • 单元测试:JUnit-4.12

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
  • 性能分析工具:JProfiler 11

  • 依赖的外部 jar 包:汉语言处理包

        <dependency>
            <groupId>com.hankcs</groupId>
            <artifactId>hanlp</artifactId>
            <version>portable-1.5.4</version>
        </dependency>

2.4 实现思路

三、接口实现

3.1 读写txt文件模块

类:TxtIOUtils

方法:

  1. readTxt:读取txt文件内容,返回String;

  1. writeTxt:将数字写入到txt文件中。

3.2 计算SimHash模块

类:SimHashUtils

方法:

  1. getHash:传入String,利用MD5计算出它的hash值,并以字符串形式输出;

  1. getSimHash:传入String,计算出它的simHash值,并以字符串形式输出。

主要流程:

  1. 分词:使用了外部依赖汉语言处理hankcs包提供的接口,把需要判断的文本分词形成这个文章的特征单词;

List<String> keywordList = HanLP.extractKeyword(str, str.length());//取出所有关键词
  1. 获取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";
                }
            }
  1. 加权、合并:通过 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++;
        }
  1. 降维:把4步算出来的序列串变成 0 1 串,形成最终的simhash。

        String simHash = "";// 储存返回的simHash值
        for (int j = 0; j < v.length; j++) {
            // 从高位遍历到低位
            if (v[j] <= 0) {
                simHash += "0";
            } else {
                simHash += "1";
            }
        }

3.3 计算海明距离模块

类:HammingUtils

方法:

  1. getHammingDistance:输入两个simHash值,计算它们的海明距离;

        for (int i = 0; i < simHash1.length(); i++) {
                // 每一位进行比较
                if (simHash1.charAt(i) != simHash2.charAt(i)) {
                    distance++;
                }
            }
  1. getSimilarity:输入两个simHash值,输出它们的相似度;

        int distance = getHammingDistance(simHash1, simHash2);
        // 通过海明距离计算出相似度,并返回
        return 0.01 * (100 - distance * 100 / 128);

通过比较差异的位数就可以得到两串文本的差异,差异的位数,称之为“海明距离”,通常认为海明距离<3的是高度相似的文本。

3.4 Main主模块

类:MainPaperChecker

主要流程:

  1. 调用TxtIOUtils,从命令行输入的绝对路径名读取对应的文件,将文件的内容转化为对应的字符串;

  1. 调用SimHashUtils,由字符串得出对应的 simHash值;

  1. 调用HammingUtils,由 simHash值求出相似度;

  1. 调用TxtIOUtils,把相似度写入最后的结果文件中。

四、性能分析

4.1 overview

4.2 方法调用情况

4.3 性能改进

由上图所展示的方法调用情况可知,程序主要消耗函数是外部依赖汉语言处理hankcs提供的接口,即分词模块,所以整体没有改进必要。

五、单元测试

5.1 读写txt文件模块测试

public class TxtIOUtilsTest {
    @Test
    public void readTxtTest() {
        // 路径存在,正常读取
        String str = TxtIOUtils.readTxt("D:/file/tests/org.txt");
        String[] strings = str.split(" ");
        for (String string : strings) {
            System.out.println(string);
        }
    }

    @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.3 计算海明距离模块测试

public class getHammingDistanceTest {
    @Test
    public void getHammingDistanceTest() {
        String str0 = TxtIOUtils.readTxt("D:/file/tests/org.txt");
        String str1 = TxtIOUtils.readTxt("D:/file/tests/org_add.txt");
        int distance = HammingUtils.getHammingDistance(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
        System.out.println("海明距离:" + distance);
    }

    @Test
    public void getSimilarityTest() {
        String str0 = TxtIOUtils.readTxt("D:/file/tests/org.txt");
        String str1 = TxtIOUtils.readTxt("D:/file/tests/org_add.txt");
        double similarity = HammingUtils.getSimilarity(SimHashUtils.getSimHash(str0), SimHashUtils.getSimHash(str1));
        System.out.println("str0和str1的相似度:" + similarity);
    }


}

测试结果:

代码覆盖率:

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("从前有座山"));
    }}

测试结果:

代码覆盖率:

七、PSP 表格

PSP2.1****

Personal Software Process Stages****

预估耗时(分钟)****

实际耗时(分钟)****

Planning

计划

40

30

· Estimate

· 估计这个任务需要多少时间

60

60

Development

开发

300

250

· Analysis

· 需求分析 (包括学习新技术)

60

30

· Design Spec

· 生成设计文档

40

30

· Design Review

· 设计复审

30

30

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

30

30

· Design

· 具体设计

90

60

· Coding

· 具体编码

300

330

· Code Review

· 代码复审

70

40

· Test

· 测试(自我测试,修改代码,提交修改)

120

150

Reporting

报告

150

120

· Test Repor

· 测试报告

40

30

· Size Measurement

· 计算工作量

40

40

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

60

30

· 合计

1430

1160

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值