第一次个人编程作业

第一次个人编程作业

这个作业属于哪个课程 计科22级12班
这个作业要求在哪里 作业要求
这个作业的目标 完成个人编程作业编码部分:论文查重

GitHub链接:https://github.com/1534063091/3122004774

一、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 6 8
Estimate 估计这个任务需要多少时间 6 8
Development 开发 127 595
Analysis 需求分析 (包括学习新技术) 10 6
Design Spec 生成设计文档 6 5
Design Review 设计复审 6 4
Coding Standard 代码规范 (为目前的开发制定合适的规范) 3 3
Design 具体设计 12 60
Coding 具体编码 21 480
Code Review 代码复审 9 7
Test 测试(自我测试,修改代码,提交修改) 60 30
Reporting 报告 124 305
Test Repor 测试报告 120 300
Size Measurement 计算工作量 1 2
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 3 3
合计 257 908

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

1.开发环境

  • Windows 11
  • jdk-22

2.开发工具

  • IntelliJ IDEA 2023.2
  • jprofiler14

3.项目依赖

  • JUnit框架

4.项目结构

Main

主要功能:主程序入口,处理命令行参数,读取文件,计算相似度,并写入输出文件。

实现过程:

  • 检查参数
    • 确保命令行参数数量为 3。若不符,输出使用说明并返回。
  • 文件路径设置
    • 从命令行参数中读取原始文件路径、抄袭文件路径和输出文件路径。
  • 验证文件存在性
    • 检查原始文件和抄袭文件是否存在。
    • 若文件不存在,通过日志记录错误并返回。
  • 读取文件内容
    • 使用 FileUtils.readFile 方法读取原始文件和抄袭文件的内容。
  • 计算相似度
    • 使用 StringUtils.calculateSimilarity 方法计算两个文件内容的相似度百分比。
  • 写入输出文件
    • 相似度结果格式化为保留两位小数的字符串,并使用 FileUtils.writeFile 方法写入指定的输出文件。
  • 异常处理
    • 捕获 IOException 异常,记录异常信息到日志中。

StringUtils

1.calculateSimilarity(String s1, String s2):

主要功能:计算两个字符串的相似度百分比。

实现过程:

  • 输入验证
    • 调用 validateInputs(s1, s2) 方法,检查字符串是否为 null。若有 null 值,抛出 IllegalArgumentException 异常。
  • 完全匹配检查
    • 如果两个字符串相等,返回 100.0(表示完全相同)。
  • 计算 Damerau-Levenshtein 距离
    • 调用 computeDamerauLevenshteinDistance(s1, s2) 方法计算两个字符串之间的编辑距离。
  • 计算相似度百分比
    • 使用公式 (1 - (double) distance / maxLength) * 100 计算相似度百分比,其中 maxLength 是两个字符串长度的较大值。
    • 特殊情况:如果最大长度为 0,直接返回 100.0。

2.validateInputs(String s1, String s2):

主要功能:验证输入字符串的有效性。

实现过程:

  • 检查 s1 和 s2 是否为 null。
  • 如果任一字符串为 null,抛出 IllegalArgumentException 异常。

3.computeDamerauLevenshteinDistance(String s1, String s2):

主要功能:计算两个字符串之间的 Damerau-Levenshtein 距离。

实现过程:

  • 调整字符串顺序
    • 确保 s1 的长度不大于 s2,通过递归调用 computeDamerauLevenshteinDistance 方法交换参数以减少计算复杂度。
  • 处理空字符串
    • 如果 s1 为空,返回 s2 的长度作为编辑距离(需要的插入操作数)。
  • 初始化矩阵
    • 创建两个一维数组 prevRow 和 currRow 用于动态规划。
    • 调用 initializeDistanceMatrix(prevRow, len1) 方法初始化第一行。
  • 动态规划计算
    • 遍历 s2 的每个字符,计算将 s1 转化为 s2 的每个前缀所需的编辑距离。
    • 处理插入、删除、替换及相邻字符交换操作,更新 currRow 的值。
    • 将 prevRow 和 currRow 进行交换,以便于下一个字符的计算。
  • 返回结果
    • prevRow[len1] 保存了最终的 Damerau-Levenshtein 距离值。

4.initializeDistanceMatrix(int[] row, int length):

主要功能: 初始化距离矩阵的第一行。

实现过程: 为矩阵的第一行赋值,表示从空字符串到任意前缀的编辑距离(即插入操作数)。

FileUtils

1.readFile(String filePath):

主要功能: 读取指定路径的文件内容。

实现过程:

  • 创建文件路径对象
    • 使用 Paths.get(filePath) 创建 Path 对象表示文件路径。
  • 检查文件是否存在
    • 使用 Files.exists(path) 检查文件是否存在。如果不存在,则抛出 IOException 异常,带有文件未找到的错误信息。
  • 读取文件内容
    • 使用 Files.readString(path, StandardCharsets.UTF_8) 方法读取文件内容,并指定使用 UTF-8 编码。
  • 返回文件内容
    • 返回读取到的文件内容字符串。

2.writeFile(String filePath, String content):

主要功能: 将内容写入指定路径的文件。

实现过程:

  • 创建文件路径对象
    • 使用 Paths.get(filePath) 创建 Path 对象表示文件路径。
  • 检查是否为目录
    • 使用 Files.isDirectory(path) 检查指定路径是否是一个目录。如果是目录,则抛出 IOException 异常,带有路径指向目录的错误信息。
  • 创建父目录
    • 使用 Files.createDirectories(path.getParent()) 创建文件的父目录(如果不存在)。这确保了在写入文件之前,所有必要的目录都已存在。
  • 写入文件内容
    • 使用 Files.writeString(path, content, StandardCharsets.UTF_8) 方法将内容写入文件,并指定使用 UTF-8 编码。这会覆盖文件中的现有内容。

三、计算模块接口部分的性能改进

1.改进思路

  • 优化空间复杂度
  • 提前终止
  • 改进异常处理
  • 算法改进
  • 代码可读性和维护

2.性能分析图

四、计算模块部分单元测试展示

1.测试函数

  • testFilesWithSameContent():测试两个文件内容完全相同的情况

  • testFilesWithDifferentContent():测试两个文件内容不同的情况

  • testEmptyFileAndNonEmptyFile():测试一个空文件和一个非空文件的情况

  • testTwoEmptyFiles():测试两个空文件的情况

  • testSingleCharacterFiles():测试两个仅有一个字符的文件

2.测试覆盖率

五、计算模块部分异常处理说明

1.命令行参数数量验证

if (args.length != 3) {
    System.out.println("Usage: java -jar main.jar <orig_file> <plagiarized_file> <output_file>");
    return;
}
  • 处理内容:检查命令行参数的数量是否为 3。
  • 异常情况:如果参数数量不正确,打印用法说明并终止程序。
  • 异常处理:这种情况属于参数错误,不涉及异常处理,而是直接通过输出消息来指导用户。

2.文件存在性检查

Path origPath = Paths.get(origFilePath);
if (!Files.exists(origPath)) {
    logger.severe("Original file does not exist: " + origFilePath);
    return;
}

Path plagiarizedPath = Paths.get(plagiarizedFilePath);
if (!Files.exists(plagiarizedPath)) {
    logger.severe("Plagiarized file does not exist: " + plagiarizedFilePath);
    return;
}
  • 处理内容:检查原始文件和抄袭文件是否存在。
  • 异常情况:如果文件不存在,使用 logger.severe 记录错误消息,并终止程序。
  • 异常处理:这部分不是捕获异常,而是检查文件的存在性并记录相关信息。此处理确保程序在尝试读取文件之前能够正确识别文件的可用性。

3.文件读取和写入操作

String originalText = FileUtils.readFile(origFilePath);
String plagiarizedText = FileUtils.readFile(plagiarizedFilePath);

String result = String.format("%.2f", similarity);
FileUtils.writeFile(outputFilePath, result);
  • 处理内容:读取文件内容和将结果写入输出文件。
  • 异常情况:如果文件操作(读取或写入)出现问题,会抛出 IOException。
  • 异常处理:IOException 被捕获并记录详细的错误信息。
catch (IOException e) {
    logger.log(Level.SEVERE, "An error occurred while processing files", e);
}
  • 异常类型:IOException
  • 处理方式:使用 logger.log 记录异常信息,包括堆栈跟踪,以便调试和问题诊断。
posted @   Honkai  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示