软件工程第二次作业-个人项目

这个作业属于哪个课程 计科23级12班
这个作业要求在哪里 个人项目
这个作业的目标 独立设计开发一个论文查重程序,并使用性能分析工具全面测试

1.项目github链接

https://github.com/wsyzc/wsyzc/tree/main/3123004415

2.PSP表格

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

3.接口的设计与实现

类结构设计

类名 说明
FileIO 负责文件内容的读取与输出
TextProcess 文本预处理模块,保留中文,英文,数字
Similar 相似度计算类,使用编辑距离算法
CheckTest 测试类,对几个类型的文本示例进行查重测试
Main 主函数类,负责各个模块的统筹调用

程序流程图

屏幕截图 2025-09-22 125902

算法关键及独到之处

算法关键

  • 核心思想:通过计算将一个字符串转换为另一个字符串所需的最少编辑操作(插入、删除、替换)次数,量化两个字符串的差异程度,再将其转换为 0~1 之间的相似度值。
  • 动态规划实现:采用二维数组dp构建状态转移表,其中dp[i][j]表示字符串s1的前i个字符与s2的前j个字符的编辑距离。通过状态转移方程(取删除、插入、替换操作的最小值)填充表格,最终dp[m][n](m、n为两字符串长度)即为全局编辑距离。
  • 复杂度特征:时间复杂度为O(m×n)(m、n分别为两个字符串的长度),空间复杂度为O(m×n)(二维数组存储),适用于中等长度文本的相似度计算。

独到之处

  • 边界处理的鲁棒性:针对两个空字符串的特殊情况,直接返回相似度 1.0,避免了除以 0 的异常及逻辑矛盾,确保算法在极端输入下的合理性。
  • 相似度转换的直观性:通过 “1 - 编辑距离 / 最长字符串长度” 的公式,将编辑距离映射为 0~1 之间的相似度值,数值越大表示文本越相似,便于结果解读。
  • 实现的简洁性:以最小化的代码量实现核心逻辑,动态规划表的初始化与填充过程清晰易懂,便于后续维护和扩展(如增加加权编辑距离等变体)。

4.单元测试

测试代码

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CheckTest {
// 测试类
private final Similar similar = new Similar();
private final TextProcess textProcess = new TextProcess();

    // 预处理文本
    private double getProcessedSimilarity(String text1, String text2) {
        String p1 = textProcess.preprocess(text1);
        String p2 = textProcess.preprocess(text2);
        return similar.getSimilarity(p1, p2);
    }

    // 1. 完全相同的中文文本(无特殊格式)
    @Test
    void testIdenticalChineseTexts() {
        String text1 = "人工智能在医疗领域的应用越来越广泛,尤其是在疾病诊断方面。";
        String text2 = "人工智能在医疗领域的应用越来越广泛,尤其是在疾病诊断方面。";
        double similarity = getProcessedSimilarity(text1, text2);
        assertEquals(1.0, similarity, 0.01, "完全相同文本预处理后应完全匹配");
    }

    // 2. 完全不同的中文文本
    @Test
    void testCompletelyDifferentChineseTexts() {
        String text1 = "计算机网络的拓扑结构包括总线型、星型和环型。";
        String text2 = "李白是唐代著名诗人,代表作有《静夜思》《望庐山瀑布》。";
        double similarity = getProcessedSimilarity(text1, text2);
        assertTrue(similarity < 0.1, "完全不同文本相似度应接近0(编辑距离特性)");
    }

    // 3. 文本A为空,文本B正常
    @Test
    void testChineseText1Empty() {
        String text1 = "";
        String text2 = "这是一段正常的中文文本。";
        double similarity = getProcessedSimilarity(text1, text2);
        assertEquals(0.0, similarity, 0.01, "空文本与非空文本相似度应为0");
    }

    // 4. 包含中文特殊标点(验证预处理逻辑)
    @Test
    void testChinesePunctuation() {
        String text1 = "中文标点包括:逗号(,)、句号(。)、书名号(《》)、顿号(、)等!";
        String text2 = "中文标点包括逗号句号书名号顿号等"; // 手动去除标点后与text1预处理结果一致
        double similarity = getProcessedSimilarity(text1, text2);
        assertEquals(1.0, similarity, 0.01, "预处理去除标点后应完全匹配");
    }

    // 5. 纯英文测试:完全相同
    @Test
    void testPureEnglishIdentical() {
        String text1 = "Artificial intelligence applications are growing rapidly in various fields.";
        String text2 = "Artificial intelligence applications are growing rapidly in various fields.";
        double similarity = getProcessedSimilarity(text1, text2);
        assertEquals(1.0, similarity, 0.01, "完全相同的纯英文文本相似度应为100%");
    }

    // 6. 纯英文测试:完全不同(主题无关)
    @Test
    void testPureEnglishDifferent() {
        String text1 = "The quick brown fox jumps over the lazy dog.";
        String text2 = "Astronomy studies celestial objects and phenomena beyond Earth's atmosphere.";
        double similarity = getProcessedSimilarity(text1, text2);
        assertTrue(similarity < 0.3, "完全不同的纯英文文本相似度应接近0");
    }

    // 7. 英文数字结合测试:部分元素相同(非前后重复)
    @Test
    void testMixedPartialElements() {
        String text1 = "Order77 has productA, price $99, date 2024-05-10.";
        String text2 = "Order77 has productB, price $88, date 2024-06-15."; // 仅订单号和年份相同
        double similarity = getProcessedSimilarity(text1, text2);
    }

    // 8. 英文数字结合测试:格式差异(标点/空格)
    @Test
    void testMixedFormatVariations() {
        String text1 = "Code: ABC123; Value=45.67, Time:10:30";
        String text2 = "Code ABC123 Value 4567 Time 1030"; // 去除标点后部分匹配
        double similarity = getProcessedSimilarity(text1, text2);
        assertTrue(similarity > 0.8, "格式差异但核心内容部分相同,相似度应>80%");
    }

    // 9. 中文分词边界测试(预处理去除空格后匹配)
    @Test
    void testChineseWordSegmentation() {
        String text1 = "南京市长江大桥";
        String text2 = "南京市长 江大桥"; // 预处理会去除空格,变为"南京市长江大桥"
        double similarity = getProcessedSimilarity(text1, text2);
        // 编辑距离计算"南京市长江大桥"与"南京市长江大桥"的差异(实际是相同的)
        assertEquals(1.0, similarity, 0.01, "预处理去除空格后应完全匹配");
    }

    // 10. 中英文混合文本(现有代码仅去除标点,不处理繁简)
    @Test
    void testMixedChineseAndEnglish() {
        String text1 = "Java语言是一种跨平台的编程语言,常用于开发企业级应用。";
        String text2 = "Java语言是一种跨平台的编程语言,常用于开发企业级应用。"; // 与text1完全相同(无繁简差异)
        double similarity = getProcessedSimilarity(text1, text2);
        assertEquals(1.0, similarity, 0.01, "完全相同的混合文本应匹配");
    }

    // 11. 相似度阈值测试(基于编辑距离的边界)
    @Test
    void testSimilarityAtThreshold() {
        String text1 = "数据结构是计算机存储、组织数据的方式,常见的有数组、链表、树等。";
        String text2 = "数据结构是计算机存储数据的方式,常见的有数组、树等结构。";
        double similarity = getProcessedSimilarity(text1, text2);
        // 实际计算值约为0.75-0.85(根据编辑距离)
        assertTrue(similarity >= 0.75 && similarity <= 0.85, "阈值附近相似度应在合理范围");
    }
}

单测覆盖率

屏幕截图 2025-09-22 142533

posted @ 2025-09-22 19:15  angelie  阅读(21)  评论(0)    收藏  举报