第一次个人编程作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13477
这个作业的目标 设计一个论文查重算法,并练习如何对程序进行性能测试和改进
我的github账号 https://github.com/scissssor/3223004776

1 PSP表格(包括预估与实际耗时)

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

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

2.1 函数关系架构

image

2.2 关键算法

2.2.1 编辑距离算法

image

2.2.2 词汇重叠率

image-20250922010522417

2.3 算法关键和独到之处

2.3.1 多算法融合策略

使用编辑距离相似度和词汇重叠率计算,可检测字符层面的差异和语义层面的内容重叠;利用加权计算综合重叠率,设置动态权重可后期调整

# 加权综合评估
combined_similarity = (0.5 * similarity_edit + 0.5 * similarity_overlap)

2.3.2 针对中文文本优化

采用jieba分词库进行精准分词并保留标点符号,并去除多余空格,统一大小写

# 使用jieba进行专业中文分词
orig_words = list(jieba.cut(orig_text))

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

初始性能分析图:

image-20250923020755373

改进优化:编辑距离算法的时间复杂度为O(m×n),对于长文本非常慢。因此使用滚动数组优化时间和空间

prev = list(range(n + 1))

for i in range(1, m + 1):
    curr = [0] * (n + 1)
    curr[0] = i
    for j in range(1, n + 1):
        if text1[i - 1] == text2[j - 1]:
            curr[j] = prev[j - 1]
        else:
            curr[j] = 1 + min(curr[j - 1],  # 插入
                              prev[j],  # 删除
                              prev[j - 1])  # 替换
    prev = curr

edit_dist = prev[n]
return 1 - (edit_dist / max(m, n))

优化后性能分析图:

image-20250923020334154

函数位置 原运行时间 优化后运行时间 原占比 优化后占比 严重程度
main.py:1(<module>) 44.9s 40.3s 100% 100%
main.py:62(main) 44.5s 39.9s 99.17% 99.24%
main.py:23(edit_distance_similarity) 43.6s 39.8s 97.23% 96.86%
_init_.py:93(initialize) 0.339s 0.279s 0.76% 0.69%
_init_.py:289(cut) 0.110s 0.093s 0.24% 0.23%

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

示例:文本预处理功能模块

测试函数类TestTextPreprocessing TestSegmentText

测试目标:验证文本预处理和分词功能

构造测试数据思路

  1. 使用中文、英文和中英混合文本
  2. 包含连续文本和分隔文本
  3. 覆盖特殊文本(空格)

测试代码

class TestTextPreprocessing:
    def test_preprocess_text_basic(self):
        """测试基础文本预处理"""
        text = "   Hello    World!   "
        result = preprocess_text(text)
        assert result == "hello world!"

    def test_preprocess_text_chinese(self):
        """测试中文文本预处理"""
        text = "   作家  写作   "
        result = preprocess_text(text)
        assert result == "作家 写作"

    def test_preprocess_text_empty(self):
        """测试空文本预处理"""
        assert preprocess_text("") == ""
        assert preprocess_text("   ") == ""
        
class TestSegmentText:
    """测试分词函数"""
    def test_segment_text_basic(self):
        """测试基础分词"""
        text = "我是中国人"
        result = segment_text(text)
        # jieba分词结果可能包含空格分隔的词汇
        words = result.split()
        assert "我" in words
        assert "是" in words
        assert "中国" in words or "中国人" in words

    def test_segment_text_english(self):
        """测试中英文混合分词"""
        text = "hello世界"
        result = segment_text(text)
        assert "hello" in result

测试覆盖率图

image-20250923220144975

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

在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。

5.1 文件操作异常

设计目标:

  1. 处理文件不存在、路径错误、权限不足等情况
  2. 提供清晰的错误信息,指导用户解决问题,避免程序因文件问题而崩溃

对应场景:用户输入了错误的文件路径,或者程序没有权限读取指定文件。

def test_file_not_found(self):
    """测试文件不存在异常"""
    with pytest.raises(FileNotFoundError):
        read_file("/不存在的路径/不存在的文件.txt")

def test_file_permission_denied(self):
    """测试文件权限不足异常"""
    # 在Windows上创建一个无权限访问的文件进行测试
    if os.name == 'nt':  # Windows系统
        system_file = "C:\\Windows\\System32\\config\\SAM"  # 系统保护文件
        if os.path.exists(system_file):
            with pytest.raises(PermissionError):
                read_file(system_file)

5.2 编码异常

设计目标:

  1. 处理文件编码不匹配的情况
  2. 支持多种常见编码格式的自动检测
  3. 提供编码问题的解决方案提示

对应场景:用户提供的文本文件使用了非UTF-8编码(如GBK、GB2312等)。

def test_file_encoding_error(self):
    """测试文件编码错误异常"""
    # 创建一个GBK编码的文件,但用UTF-8读取
    with tempfile.NamedTemporaryFile(mode='wb', delete=False) as f:
        f.write("中文内容".encode('gbk'))
        temp_path = f.name
    
    try:
        # 默认使用UTF-8读取会导致编码错误
        with pytest.raises(UnicodeDecodeError):
            read_file(temp_path)
    finally:
        os.unlink(temp_path)

5.3 内存异常

设计目标:

  1. 处理大文件导致的内存溢出问题
  2. 对超长文本进行分块处理,避免内存爆炸

对应场景:用户处理非常大的文本文件(如整本书籍对比)。

def test_memory_overflow_prevention(self):
    """测试内存溢出防护机制"""
    # 创建超长文本测试内存处理
    huge_text1 = "A" * 1000000  # 100万字符
    huge_text2 = "B" * 1000000
    
    # 测试是否能正常处理而不内存溢出
    try:
        similarity = edit_distance_similarity_optimized(huge_text1, huge_text2)
        assert 0.0 <= similarity <= 1.0
    except MemoryError:
        pytest.skip("内存不足,跳过超长文本测试")

5.4 输入验证异常

设计目标:

  1. 验证输入参数的合法性和类型安全性,防止无效参数导致的计算错误
  2. 提供清晰的参数要求说明

对应场景:程序调用者传入了错误类型的参数或空值。

def test_invalid_input_type(self):
    """测试无效输入类型异常"""
    with pytest.raises(TypeError):
        edit_distance_similarity(123, "文本")  # 数字而不是字符串
    
    with pytest.raises(TypeError):
        word_overlap_ratio("字符串", ["列表"])  # 字符串而不是列表

def test_empty_text_handling(self):
    """测试空文本处理"""
    # 空文本应该返回0相似度,而不是抛出异常
    similarity = edit_distance_similarity("", "非空文本")
    assert similarity == 0.0
    
    ratio = word_overlap_ratio([], ["词汇"])
    assert ratio == 0.0
posted on 2025-09-23 22:23  scissor0611  阅读(7)  评论(0)    收藏  举报