第一次编程作业

这个作业属于哪个课程 <23级软件工程>
这个作业要求在哪里 <作业要求的链接>
这个作业的目标 学习PSP2.1思想下的程序设计实现方法

作业文件链接

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

程序总体设计

需求分析

本次作业要求程序从两份文件读入文字数据,分析文字数据特征并进行比较,最后输出相似度到另一文件中。

根据设计需求,由于之前没有接触过相关内容,因此在网上找了一篇以余弦相似度比较文字相关性的博客作为参考。

程序具体设计

程序各接口设计与实现

本次作业设计的程序较为简单,仅包含三个模块,且各模块仅有一个接口

  1. 主模块

主模块的主要作用是调用其他模块和输出答案数据,其接口名为mainfunction()

  1. 数据读取模块

数据读取模块的作用是用硬盘上读取数据到程序中,其接口为getfiledata(num)

  1. 计算模块

计算模块的作用是计算两个文本的相似度,其接口为getresult(paragraph1,paragraph2)

其逻辑如下:

main

性能改进

程序性能分析如下:

pichom20250308-2

可见程序运行主要耗时于结果计算中

其函数代码如下:

def getresult(paragraph1,paragraph2):
    interruption = ["\n", "", " "]  # 分词后过滤子项的筛选器
    paragraph1_cut = [i for i in jieba.cut(paragraph1, cut_all=True) if not i in interruption]
    paragraph2_cut = [i for i in jieba.cut(paragraph2, cut_all=True) if not i in interruption]  # 分词
    word_set = set(paragraph1_cut).union(set(paragraph2_cut))  # 创建分词并集
    word_dict = dict()  # 创建分词编码词典
    t = 0 
    for word in word_set:
        word_dict[word] = t
        t += 1
    paragraph1_cut_node = [word_dict[word] for word in paragraph1_cut]  # 将词按词典进行编码
    paragraph1_cut_node_loc =  [0] * len(word_dict)
    t = 0;
    for rank in paragraph1_cut_node:
        paragraph1_cut_node_loc[rank] += 1  # 根据编码后词组映射向量
    paragraph2_cut_node = [word_dict[word] for word in paragraph2_cut]  # 将词按词典进行编码
    t = 0;
    paragraph2_cut_node_loc = [0] * len(word_dict)
    for rank in paragraph2_cut_node:
        paragraph2_cut_node_loc[rank] += 1
    sum = 0
    sq1 = 0
    sq2 = 0
    for t in range(len(word_dict)):  # 进行余弦相似度计算
        sum += paragraph1_cut_node_loc[t] * paragraph2_cut_node_loc[t]
        sq1 += pow(paragraph1_cut_node_loc[t], 2)
        sq2 += pow(paragraph2_cut_node_loc[t], 2)

    try:
        result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
    except ZeroDivisionError:
        result = 0.0
    return result

为改进计算效率,这里尽可能精简了筛选器,在减小了筛选的支出的同时也缩小了词典的大小。

程序测试

单元测试展示

单元覆盖测试率

pichom20250308

1.测试文件位置出错情况

    @unittest.expectedFailure
    def test_wrong_location(self):#测试文件位置出错情况
        getfiledata(1)

2.测试完全相同情况

    def test_same_text(self):#测试完全相同情况
        origtext="早上好,大学生。"
        tartext="早上好,大学生。"
        self.assertEqual(getresult(origtext,tartext),1)

3.测试完全不同情况

    def test_diff_text(self):#测试完全不同情况
        origtext="早上好,大学生。"
        tartext="今天天气怎么样"
        self.assertEqual(getresult(origtext,tartext),0)

4.测试单项空时情况

    def test_1_emp_text(self):#测试单项空时情况
        origtext="早上好,大学生。"
        tartext=""
        self.assertEqual(getresult(origtext,tartext),0)

5.测试单项空时情况

    def test_2_emp_text(self):#测试双项空时情况
        origtext=""
        tartext=""
        self.assertEqual(getresult(origtext,tartext),0)

6.测试纯标点情况

def test_interruption_text(self):#测试纯标点情况
    origtext="......"
    tartext="......"
    self.assertEqual(getresult(origtext,tartext),1)

7.测试程序主入口

    def test_main_text(self):#测试程序主入口
        subprocess.run(["python","main.py","1.txt","2.txt","3.txt"])
        self.assertEqual(1,1)#成功运行到这一步即可

8.测试中长文本情况

def test_long_text(self):#测试中长文本情况
    origtext="家作要表达与之朝夕相处的现实,他常常会到感以难承受蜂,拥而来真的实乎几都在说着诉丑恶和阴险,就怪在怪这里,为什么丑恶的事物总是身在边,而美好的事物远却在海。角换话说句,人的友爱和情往同往是作只为情来绪到,而相反事的则实是伸手便触可及正。像一位诗人所表达的:人类无法忍受太多的真实也。这有样的作家,一生都在解决自和现实我的紧张关系,克福纳是为最成功的子例他找,到了一条温和的途径他描写,中状态间的事物,同时容了包美与好丑恶,他将美国南方现的实放到了历史和人文精神中之这,是真意正义上的学文现实,因为它连接过去着和将来。"
    tartext="相家要表与之 夕 处的以实,他常常而感到难实承乎,在拥说来的真现几受都蜂诉会着丑里和阴险,怪就怪事物恶,为什么丑恶的在这总是却身边,而美好的事物在远在友角和同句往说,是的海爱。换到话往只人作为情绪来情,便相反的事正则是伸手而可触及。实像一位诗人受表达的:实类无法忍所太多的真人生也在这样的作和现一的都有解决自我家,是。紧张关的,福克纳实最为一功系和的,他找他了成中温状子途事物到描写包间例美的径,,同时条容了态好的现恶放到将美国南方与丑神,他了历是和人文精实之中,这实真正意义上的着过现和,来为它连接文学去史将因成"
    self.assertEqual(getresult((origtext,tartext)<1 and getresult(origtext,tartext)>0),True)

9.测试纯空白情况

def test_blank_text(self):#测试纯空白情况
    origtext="      "
    tartext="      "
    self.assertEqual(getresult(origtext,tartext),0)

10.测试纯数字情况

def test_num_text(self):#测试纯数字情况
    origtext="1234567887654321"
    tartext="8463725113245768"
    self.assertEqual(getresult(origtext,tartext),0)

异常处理

由于本程序较为简单,因此所需处理的异常也相对较少

1.在读取文件时没有发现相应文件:

处理方法如下:

try:
    file = open(sys.argv[num], "r", encoding="utf-8")
except FileNotFoundError:
    print("第"+num+"个文件路径输入错误\n")
    exit(1)

测试单元见测试1

2.在文本中有一项为空文本导致最后计算时出现除数为0错误

处理方法如下:

try:
    result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
except ZeroDivisionError:
    result = 0.0

测试单元见测试4

posted @ 2025-03-08 23:09  听风的雨  阅读(46)  评论(0)    收藏  举报