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

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/homework/13468
这个作业的目标 完成论文查重算法设计以及单元测试用例的设计

一、PSP表格(预计时间)

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

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

1.计算模块划分

以下表格展示了程序的模块划分、对应函数及功能说明:

模块 函数 功能说明
文件读取 read_file(path) 读取指定路径的文件内容
文本预处理 normalize_text(s) 去除空白字符、标点,并将英文转小写,规范化文本
LCS 计算模块 lcs_length(a, b) 计算两段文本的最长公共子序列长度,使用滚动数组减少空间复杂度
分段重复率计算模块 compute_duplicate_rate(orig_text, plag_text, as_percentage=True) 对超长文本进行分段LCS,计算整体重复率
主程序 main() 命令行参数解析、文件存在性检查、调用重复率计算,并输出结果到文件

2.算法关键

(1) 文本规范化(normalize_text)
去除所有空白字符和标点,统一英文为小写。
(2) LCS 动态规划(LCS,lcs_length)
衡量连续字符的最长匹配长度。
(3) 分段处理(compute_duplicate_rate_segmented)
对长文本分段,降低内存和计算压力,可以灵活调整段长度控制精度和性能。

3.独到之处

(1) 滚动数组优化 LCS 算法,节省内存。
(2) 自定义文本规范化
采用正则同时处理中文、英文标点,保证不同语言文本匹配准确;去空白、去标点和大小写统一,避免无关字符影响重复率。
(3) 分段 LCS
既能检测大段连续抄袭,又能处理超长文本,可以根据实际文本长度和性能需求调整 seg_len。

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

1.性能分析

改进前:
在初始实现中,对比文本计算重复率时,发现 lcs_length 函数 是程序的主要性能瓶颈。

屏幕截图 2025-09-20 205359
屏幕截图 2025-09-20 205028

图中显示 lcs_length 耗时87s,占据程序大部分执行时间,是主要性能消耗函数。

改进后:

屏幕截图 2025-09-20 204501
屏幕截图 2025-09-20 204720
耗时2.9s,优化后时间显著减少。

2.性能改进思路

(1) 滚动数组优化 LCS
原始 LCS 算法需要 O(nm) 空间存储二维 DP 矩阵。改进方法:只保留前一行和当前行数据,使用两个一维数组交替存储,空间复杂度从 O(nm) 降到 O(m)。

(2) 分段 LCS
对长文本直接计算 LCS 会导致时间复杂度过高,改进为按段分段计算LCS,每段长度 seg_len。

3. 所花费时间记录

优化步骤 所花时间(分钟) 说明
性能分析 10 使用 cProfile 等性能分析工具,找出程序瓶颈(主要在 lcs_length)
空间优化 30 将二维 DP 数组改为两行滚动数组,减少内存占用
行列交换优化 10 对 lcs_length 内循环调整顺序,确保列长度小,提高缓存效率
分段计算优化 30 使用 compute_duplicate_rate_segmented,将文本分段计算 LCS,降低时间复杂度
测试与验证 10 对比优化前后结果,确保重复率计算正确
合计 90 性能优化总耗时

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

1.部分单元测试代码

# ----------------- 文件读取测试 -----------------
def test_read_file():
    with tempfile.NamedTemporaryFile("w+", delete=False, encoding="utf-8") as tmp:
        tmp.write("hello world")
        tmp_path = tmp.name
    content = pc.read_file(tmp_path)
    assert content == "hello world"
    os.remove(tmp_path)


# ----------------- 文本规范化测试 -----------------
def test_normalize_text():
    text = "今天 是 星期天,天气晴!Hello, World。"
    normalized = pc.normalize_text(text)
    # 按新代码逻辑,空格和标点去掉,英文小写化
    assert normalized == "今天是星期天天气晴helloworld"


# ----------------- LCS 测试 -----------------
def test_lcs_length_identical():
    assert pc.lcs_length("abc", "abc") == 3

def test_lcs_length_partial():
    assert pc.lcs_length("abcdef", "ace") == 3

def test_lcs_length_empty():
    assert pc.lcs_length("", "abc") == 0
    assert pc.lcs_length("abc", "") == 0

2.测试函数说明与数据构造思路

测试函数 测试目标 构造测试数据思路
test_read_file 验证文件读取功能是否正确 使用 tempfile 创建临时文件,写入已知文本,然后读取验证内容是否一致
test_normalize_text 验证文本规范化功能 构造包含空格、标点、英文大写的字符串,检查空格和标点是否去掉,并将英文转换为小写
test_lcs_length_identical 验证 LCS 计算完全相同字符串 构造两个完全相同的字符串,预期 LCS 长度等于字符串长度
test_lcs_length_partial 验证 LCS 计算部分相同字符串 构造部分相同的字符串,预期 LCS 长度为公共子序列长度
test_lcs_length_empty 验证 LCS 计算空字符串情况 构造空字符串与非空字符串组合,预期 LCS 长度为 0
test_compute_duplicate_rate_segmented_identical 验证分段重复率计算完全相同文本 构造完全相同的原文和抄袭文本,重复率应接近 100%
test_compute_duplicate_rate_segmented_partial 验证分段重复率计算部分重复文本 构造原文和部分相同的抄袭文本,计算 LCS 后重复率应接近公共字符比例(按分段算法计算)
test_compute_duplicate_rate_segmented_empty_orig 验证分段重复率计算原文为空 构造原文为空字符串,抄袭文本任意内容,重复率应为 0
test_compute_duplicate_rate_segmented_empty_copy 验证分段重复率计算抄袭文本为空 构造原文非空,抄袭文本为空,重复率应为 0
test_compute_duplicate_rate_segmented_whitespace_only 验证分段重复率计算仅空格情况 构造原文和抄袭文本仅包含空格,重复率应为 0
test_compute_duplicate_rate_segmented_punctuation 验证分段重复率计算含标点文本 构造含中文/英文标点的文本,标点应被忽略,重复率接近文字内容比例
test_main_correct_execution 验证 main 函数执行流程 使用临时目录创建原文和抄袭文本文件,运行 main 函数,检查输出为数字字符串且保留两位小数
test_main_missing_file 验证文件不存在时程序异常退出 指定不存在的文件路径,检查程序是否抛出 SystemExit 异常

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

屏幕截图 2025-09-20 211044

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

1.文件不存在异常

  • 设计目标:保证程序在用户输入的原文或抄袭文件路径不存在时,能够及时提示并安全退出,而不会出现 FileNotFoundError
  • 处理方式
if not os.path.isfile(orig_path):
    print("原文文件不存在:", orig_path)
    sys.exit(2)
if not os.path.isfile(plag_path):
    print("抄袭版文件不存在:", plag_path)
    sys.exit(2)
  • 单元测试示例
def test_main_missing_file():
    sys.argv = ["plagiarism_checker.py", "nofile.txt", "also_no.txt", "out.txt"]
    with pytest.raises(SystemExit):
        pc.main()
  • 错误场景说明
    用户提供的原文文件或抄袭文件路径不存在,程序会捕获该情况并退出,避免崩溃。

2.原文为空异常

  • 设计目标:避免计算重复率时出现除零错误,确保原文为空也能返回合理值。
  • 处理方式
def compute_duplicate_rate_segmented(orig_text, plag_text):
    o = normalize_text(orig_text)
    if len(o) == 0:
        return 0.0
  • 单元测试示例
def test_compute_duplicate_rate_segmented_empty_orig():
    rate = pc.compute_duplicate_rate_segmented("", "任意文本")
    assert rate == pytest.approx(0.0)
  • 错误场景说明
    原文文件内容为空,程序返回重复率 0,而不会报错。

3.抄袭文本为空异常

  • 设计目标:确保重复率计算在抄袭文本为空时返回合理值,而不会报错。
  • 处理方式
def compute_duplicate_rate_segmented(orig_text, plag_text):
    p = normalize_text(plag_text)
    # 原文不为空时,重复率计算结果为 0
  • 单元测试示例
def test_compute_duplicate_rate_segmented_empty_copy():
    rate = pc.compute_duplicate_rate_segmented("原文有内容", "")
    assert rate == pytest.approx(0.0)
  • 错误场景说明
    抄袭文本为空,程序返回重复率 0,而不会报错。

4.原文或抄袭文本全为空格异常

  • 设计目标:确保重复率计算在文本只包含空格时返回合理值。
  • 处理方式
def compute_duplicate_rate_segmented(orig_text, plag_text):
    o = normalize_text(orig_text)
    p = normalize_text(plag_text)
    if len(o) == 0:
        return 0.0
  • 单元测试示例
def test_compute_duplicate_rate_segmented_whitespace_only():
    rate = pc.compute_duplicate_rate_segmented("     ", "  ")
    assert rate == pytest.approx(0.0)
  • 错误场景说明
    原文和抄袭文本只包含空格,程序返回重复率 0。

5.文本含标点异常

  • 设计目标:保证重复率计算时忽略标点符号,避免影响结果。
  • 处理方式
def normalize_text(s):
    import re
    s = re.sub(r"\s+", "", s)
    s = re.sub(r"[,。!?;:、,.!?;:\"'()()\[\]【】<>《》—\-…·/\\]", "", s)
    s = s.lower()
    return s
  • 单元测试示例
def test_compute_duplicate_rate_segmented_punctuation():
    rate = pc.compute_duplicate_rate_segmented("今天,天气晴!", "今天天气晴")
    assert rate >= 90.0
  • 错误场景说明
    原文或抄袭文本含有中文或英文标点,程序忽略标点计算重复率,保证结果准确。

六、PSP表格(实际时间)

PSP2.1 Personal Software Process Stages 预估耗时 (分钟) 实际耗时 (分钟)
Planning 计划 30 30
Estimate 估计这个任务需要多少时间 120 200
Development 开发 360 380
Analysis 需求分析 (包括学习新技术) 60 80
Design Spec 生成设计文档 40 60
Design Review 设计复审 15 15
Coding Standard 代码规范 (为目前的开发制定合适的规范) 15 15
Design 具体设计 50 60
Coding 具体编码 260 320
Code Review 代码复审 40 50
Test 测试(自我测试,修改代码,提交修改) 50 80
Reporting 报告 90 120
Test Repor 测试报告 50 50
Size Measurement 计算工作量 30 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 50 30
合计 1260 1520
posted @ 2025-09-22 12:02  bzxxxxxx  阅读(27)  评论(0)    收藏  举报