第一次编程作业
| 这个作业属于哪个课程 | <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 |
程序总体设计
需求分析
本次作业要求程序从两份文件读入文字数据,分析文字数据特征并进行比较,最后输出相似度到另一文件中。
根据设计需求,由于之前没有接触过相关内容,因此在网上找了一篇以余弦相似度比较文字相关性的博客作为参考。
程序具体设计
程序各接口设计与实现
本次作业设计的程序较为简单,仅包含三个模块,且各模块仅有一个接口
- 主模块
主模块的主要作用是调用其他模块和输出答案数据,其接口名为mainfunction()
- 数据读取模块
数据读取模块的作用是用硬盘上读取数据到程序中,其接口为getfiledata(num)
- 计算模块
计算模块的作用是计算两个文本的相似度,其接口为getresult(paragraph1,paragraph2)
其逻辑如下:
性能改进
程序性能分析如下:

可见程序运行主要耗时于结果计算中
其函数代码如下:
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
为改进计算效率,这里尽可能精简了筛选器,在减小了筛选的支出的同时也缩小了词典的大小。
程序测试
单元测试展示
单元覆盖测试率

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
浙公网安备 33010602011771号