第一次个人编程作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 作业要求
这个作业的目标 用java实现论文查重的功能,学会PSP表格的使用

Github链接:github地址

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 45
Estimate 估计这个任务需要多少时间 15 10
Development 开发 600 590
Analysis 需求分析 (包括学习新技术) 120 180
Design Spec 生成设计文档 40 60
Design Review 设计复审 10 10
Coding Standard 代码规范 (为目前的开发制定合适的规范) 10 10
Design 具体设计 20 15
Coding 具体编码 180 190
Code Review 代码复审 20 30
Test 测试(自我测试,修改代码,提交修改) 60 80
Reporting 报告 50 60
Test Repor 测试报告 40 50
Size Measurement 计算工作量 10 10
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 15 20
合计 1220 1360

模块接口的设计与实现过程

实现关键:

主要通过读取文件内容,生成SimHash值,再利用Hamming距离计算两个文本的相似度。项目的独到之处在于使用了中文分词技术和SimHash加权算法,使其能够快速处理大规模文本数据。

模块设计:

IOUtils: 负责文件操作,包括读取文件、写入文件、清空文件和获取文件夹中的所有文件路径。
SimHash: 负责计算SimHash值,包括计算MD5哈希值和从文本生成SimHash值。
HammingUtils: 负责计算Hamming距离和相似度。
Main: 负责协调其他模块,执行主要的流程,包括读取文件、计算SimHash、计算相似度、输出结果。

函数设计:

IOUtils类

readTxt(String txtPath): 读取文件内容并返回字符串。
writeTxt(String content, String txtPath): 将字符串内容写入文件。
writeTxt(double value, String txtPath): 将double类型的内容写入文件。
clearFile(String txtPath): 清空文件内容。
getFilePaths(String folderPath): 获取文件夹中所有文件的路径。

SimHash类

getHash(String str): 计算字符串的MD5哈希值并返回二进制字符串。
getSimHash(String str): 计算字符串的SimHash值。

HammingUtils类

getHammingDistance(String simHash1, String simHash2): 计算两个SimHash值的Hamming距离。
getSimilarity(int distance): 通过Hamming距离计算相似度。

Main类

main(String[] args): 主函数,执行整体流程,包括读取主文件和比较文件、计算SimHash值和相似度、输出结果。

模块之间的关系:

Main 类:

调用 IOUtils 类的方法来读取文件内容和写入结果。
使用 SimHash 类的方法计算SimHash值。
调用 HammingUtils 类的方法计算Hamming距离和相似度。

SimHash 类:

依赖于getHash方法来获取单词的MD5哈希值。
在 getSimHash 方法中,调用getHash生成特征向量。

HammingUtils 类:

计算两个SimHash值的Hamming距离,并通过这个距离计算相似度。

关键函数流程图:

模块接口部分的性能改进

在改进计算模块性能上花了大约20分钟,将IOUtils中的文件读取改为InputStreamReader,确保在读取包含不同编码的大文件时效率更高等

性能分析图:由JProfiler的性能分析工具自动生成


模块部分单元测试展示

SimHash 类的单元测试

@Test
public void testGetSimHash() {
    String content = "Hello, World!";
    String simHash = SimHash.getSimHash(content);
    String expectedSimHash = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; // Expected value should be calculated based on the method
    assertEquals(expectedSimHash, simHash);
}

使用固定的字符串"Hello, World!"计算SimHash值,并与预期的SimHash值进行比对。预期值需要根据实际SimHash算法计算得到

HammingUtils 类的单元测试

@Test
public void testGetHammingDistance() {
    String simHash1 = "11010101010101010101010101010101";
    String simHash2 = "11010101010101010101010101010001";
    int distance = HammingUtils.getHammingDistance(simHash1, simHash2);
    assertEquals(1, distance);
}

测试SimHash值:使用已知的SimHash值对来计算Hamming距离,确保计算结果正确。这里选择了两个仅在最后一位不同的SimHash值来计算距离

单元测试得到的测试覆盖率截图:

模块部分异常处理说明

文件读取异常:

点击查看代码
    @Test
    public void testReadTxt_FileNotFound() {
        // 测试读取一个不存在的文件
        assertThrows(IOException.class, () -> {
            IOUtils.readTxt("nonexistent_file.txt");
        });
    }

当文件的写入权限不足:

点击查看代码
    @Test
    public void testWriteTxt_NoWritePermission() {
        // 测试写入一个不可写的文件
        assertThrows(IOException.class, () -> {
            IOUtils.writeTxt("Some content", "/path/to/protected_file.txt");
        });
    }

处理哈希算法错误:

点击查看代码
    @Test
    public void testGetHash_InvalidAlgorithm() {
        // 模拟一个无效的哈希算法场景
        // 这通常需要通过Mock或特殊配置模拟,但在标准环境中MD5始终可用
        assertThrows(RuntimeException.class, () -> {
            SimHash.getHash("test");
        });
    }

处理哈希长度不一致:

点击查看代码
    @Test
    public void testGetHammingDistance_LengthMismatch() {
        // 测试长度不匹配的海明距离计算
        assertThrows(IllegalArgumentException.class, () -> {
            HammingUtils.getHammingDistance("1101", "11010"); // 不同长度
        });
    }

主文件路径无效:

点击查看代码
    @Test
    public void testMain_InvalidFilePath() {
        // 模拟主文件或比较文件路径无效的场景
        assertThrows(IOException.class, () -> {
            // 假设主函数中的文件路径无效
            Main.main(new String[]{});
        });
    }

运行结果

命令行输入,输出的结果:

文件保存结果:

posted @ 2024-09-13 16:56  江川123  阅读(38)  评论(0编辑  收藏  举报