软工个人项目-论文查重

news/2024/11/16 12:01:48/文章来源:https://www.cnblogs.com/c-z-j/p/18411394

软工个人项目-论文查重

这个作业属于哪个课程 广工计院计科34班软工
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229
这个作业的目标 个人独立完成论文查重代码,进一步了解项目开发的流程,学会运用工具分析消除警告,运用性能分析工具进行改进提高

GitHub地址

一、需求

题目:论文查重

描述如下:

设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。

  • 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
  • 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。

要求输入输出采用文件输入输出,规范如下:

  • 命令行参数给出:论文原文的文件的绝对路径
  • 命令行参数给出:抄袭版论文的文件的绝对路径
  • 命令行参数给出:输出的答案文件的绝对路径

我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。

注意:答案文件中输出的答案为浮点型,精确到小数点后两位

二、PSP表

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

三、模块接口的设计和实现过程

1. 文件读取模块 (read_file)

  • 接口设计
    • 输入:file_path(文件路径)。
    • 输出:文件的内容(字符串),或者在发生错误时返回 None

2. 文本预处理模块 (preprocess_text)

  • 输入:text(原始文本)。

  • 输出:处理后的分词列表。

  • 使用正则表达式 re.sub(r"[^\w\s]", "", text) 去除标点符号、转义字符和其他特殊字符,只保留文字和空格,确保文本干净,避免噪声影响分词。

3. 余弦相似度计算模块 (calculate_cosine_similarity)

  • 输入:tokens1tokens2(两个分词列表)。

  • 输出:两篇文章的余弦相似度值。

  • 使用 gensim.corpora.Dictionary 来构建词典,将分词结果映射到向量空间模型(VSM)。

  • 利用 gensim.similarities.Similarity 模块计算余弦相似度。

4. 结果保存模块 (save_result)

  • 输入:result_path(保存结果的文件路径),similarity_score(计算得到的相似度)。
  • 输出:无,直接将相似度结果写入指定文件。

5. 命令行参数解析与主流程控制 (main)

  • 通过 argparse.ArgumentParser 获取用户输入的文件路径,包括原文、抄袭文和结果保存路径。
  • 实现了整个程序的主流程,包括:读取文件、预处理文本、计算相似度、保存结果等。

独到之处

使用 jieba 库进行中文分词,特别适合处理中文文本中的复杂词语分界问题。

使用了 gensim 库,其性能和扩展性在处理大规模文本相似度问题上优越。

结合命令行参数和异常处理,用户可以根据需要指定不同文件路径,且在程序运行过程中有详细的错误提示,便于排查问题。

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

性能分析

使用python的第三方库line_profiler实现

read_file()

preprocess_text()

calculate_cosine_similarity()

save_result()

main()

我们可以得到函数preprocess_text()的用时最长,并且耗时达到0.233673 s

性能改进

正则表达式优化:当前使用的正则表达式 re.sub(r"[^\w\s]", "", text) 在大文本上可能效率不高。可以使用预编译的正则表达式来减少重复编译的开销。

五、模块部分单元测试展示

1.单元测试代码

import unittest
import jieba
import os
import re
from main import read_file, preprocess_text, calculate_cosine_similarity, save_resultclass TestSimilarityFunctions(unittest.TestCase):def setUp(self):# 创建两个测试文本self.test_text1 = "这是一个用于测试的文本。"self.test_text2 = "这个文本和第一个文本有一些相似之处。"self.empty_text = ""self.similarity_score_path = "test_similarity_score.txt"# 创建测试文件with open("test_file1.txt", "w", encoding="utf-8") as f1:f1.write(self.test_text1)with open("test_file2.txt", "w", encoding="utf-8") as f2:f2.write(self.test_text2)with open("empty_file.txt", "w", encoding="utf-8") as f3:f3.write(self.empty_text)def tearDown(self):# 删除测试文件os.remove("test_file1.txt")os.remove("test_file2.txt")os.remove("empty_file.txt")if os.path.exists(self.similarity_score_path):os.remove(self.similarity_score_path)def test_read_file(self):# 测试读取文件功能content1 = read_file("test_file1.txt")content2 = read_file("test_file2.txt")self.assertEqual(content1, self.test_text1)self.assertEqual(content2, self.test_text2)# 测试读取空文件content = read_file("empty_file.txt")self.assertEqual(content, self.empty_text)# 测试读取不存在的文件content = read_file("nonexistent_file.txt")self.assertIsNone(content)def test_preprocess_text(self):# 测试文本预处理功能tokens1 = preprocess_text(self.test_text1)tokens2 = preprocess_text(self.test_text2)# 输出实际分词结果以调试print("分词结果1:", tokens1)print("分词结果2:", tokens2)# 手动检查jieba分词的实际结果test_text1_cleaned = re.sub(r"[^\w\s]", "", self.test_text1)test_text2_cleaned = re.sub(r"[^\w\s]", "", self.test_text2)expected_tokens1 = jieba.lcut(test_text1_cleaned)expected_tokens2 = jieba.lcut(test_text2_cleaned)# 断言实际预处理结果与分词结果一致self.assertEqual(tokens1, expected_tokens1)self.assertEqual(tokens2, expected_tokens2)# 测试空文本empty_tokens = preprocess_text(self.empty_text)self.assertEqual(empty_tokens, [])def test_calculate_cosine_similarity(self):# 测试余弦相似度计算tokens1 = preprocess_text(self.test_text1)tokens2 = preprocess_text(self.test_text2)similarity_score = calculate_cosine_similarity(tokens1, tokens2)# 验证相似度是否为合理范围(0到1之间)self.assertGreaterEqual(similarity_score, 0.0)self.assertLessEqual(similarity_score, 1.0)# 测试两个完全相同的文本identical_tokens = preprocess_text(self.test_text1)similarity_score_identical = calculate_cosine_similarity(identical_tokens, identical_tokens)self.assertAlmostEqual(similarity_score_identical, 1.0, places=4)# 测试空文本和非空文本的相似度empty_tokens = preprocess_text(self.empty_text)similarity_score_with_empty = calculate_cosine_similarity(empty_tokens, tokens1)self.assertEqual(similarity_score_with_empty, 0.0)def test_save_result(self):# 测试保存相似度结果到文件similarity_score = 0.85save_result(self.similarity_score_path, similarity_score)with open(self.similarity_score_path, 'r', encoding="utf-8") as f:content = f.read()self.assertEqual(content, "文章相似度:0.85")# 测试保存到无权限文件路径(模拟异常情况)try:save_result("/invalid_path/test_similarity_score.txt", similarity_score)except Exception as e:self.assertIsInstance(e, Exception)if __name__ == '__main__':unittest.main()

2测试结果图

3.测试数据与测试函数构造思路

①测试文件的读取功能 (test_read_file)

思路:
目标:验证 read_file 函数在读取不同文件内容时能否返回正确的结果,尤其在文件存在、内容为空以及文件不存在等情况下。
测试数据设计:
test_file1.txt 和 test_file2.txt:两个带有不同内容的测试文件。
empty_file.txt:一个内容为空的文件,用于测试函数处理空文件的能力。
nonexistent_file.txt:模拟一个不存在的文件路径,用于验证函数处理文件路径无效的情况。
检查点:
验证 read_file 是否返回文件的实际内容。
验证空文件是否返回空字符串。
验证读取不存在的文件时,函数是否返回 None。

②测试文本预处理功能 (test_preprocess_text)

思路:
目标:验证 preprocess_text 函数是否能正确去除标点符号、特殊字符,并使用 jieba 进行分词,特别是在空文本和正常文本输入时的表现。
测试数据设计:
self.test_text1 和 self.test_text2:这两个文本用于测试一般情况下的分词效果。
self.empty_text:空字符串,用于测试空文本是否返回空分词结果。
检查点:
验证 preprocess_text 是否正确移除标点符号和特殊字符。
使用 jieba.lcut 手动分词进行对比,确保函数的输出与 jieba 分词结果一致。
确保对空文本的处理返回空列表。
独特之处:
输出分词结果供调试使用,以便在输出不符预期时帮助定位问题。

③测试余弦相似度计算功能 (test_calculate_cosine_similarity)

思路:
目标:验证 calculate_cosine_similarity 函数是否能正确计算两个分词结果之间的余弦相似度,且在不同文本、相同文本及空文本情况下返回合理的结果。
测试数据设计:
self.test_text1 和 self.test_text2:用于测试两个不同文本之间的相似度计算。
self.test_text1 与自身比较:用于测试相同文本的相似度,应返回接近 1.0 的值。
空文本:验证空文本与其他文本的相似度,结果应为 0.0。
检查点:
验证相似度结果是否在合理范围(0.0 - 1.0)。
检查两个相同文本的相似度是否接近 1.0。
确保空文本与非空文本比较时相似度为 0.0。

④测试结果保存功能 (test_save_result)

思路:
目标:验证 save_result 函数能否正确将相似度结果保存到指定的文件中,测试普通文件路径和异常情况下(如无效路径)的表现。
测试数据设计:
相似度得分 (similarity_score = 0.85):用来测试是否能正确写入文件。
self.similarity_score_path:用于保存测试结果的路径,测试能否成功写入文件并读取结果验证。
无效文件路径 (/invalid_path/test_similarity_score.txt):用于测试写入文件失败的处理(模拟文件路径无权限等问题)。
检查点:
检查文件内容是否与预期一致(即 "文章相似度:0.85")。
在无效路径下写入文件时,检查函数是否抛出适当的异常。

4.覆盖率

六、模块部分异常处理说明

1. read_file 函数的异常处理

def read_file(file_path):try:with open(file_path, 'r', encoding='UTF-8') as file:return file.read()except FileNotFoundError:print(f"错误:文件 {file_path} 未找到。请检查路径是否正确。")return Noneexcept Exception as e:print(f"读取文件 {file_path} 时出错:{e}")return None
  • FileNotFoundError: 捕获文件不存在的情况,提示用户检查路径,避免程序崩溃,返回 None
  • 通用异常 (Exception): 捕获其他可能的文件读取错误(如权限问题等),输出错误信息并返回 None

2. calculate_cosine_similarity 函数的异常处理

def calculate_cosine_similarity(tokens1, tokens2):try:# 创建词典并计算余弦相似度dictionary = gensim.corpora.Dictionary([tokens1, tokens2])corpus = [dictionary.doc2bow(tokens) for tokens in [tokens1, tokens2]]similarity_index = gensim.similarities.Similarity('-Similarity-index', corpus, num_features=len(dictionary))cosine_similarity = similarity_index[corpus[0]][1]return cosine_similarityexcept Exception as e:print(f"计算相似度时出错:{e}")return None
  • 通用异常 (Exception): 捕获所有在计算余弦相似度过程中可能发生的错误,如词典生成或相似度计算错误,输出错误信息并返回 None

3. save_result 函数的异常处理

def save_result(result_path, similarity_score):try:with open(result_path, 'w', encoding="utf-8") as result_file:result_file.write(f"文章相似度:{similarity_score:.2f}")except Exception as e:print(f"写入文件 {result_path} 时出错:{e}")return
  • 通用异常 (Exception): 捕获文件写入时的所有异常(如路径错误或权限问题),输出错误信息并继续执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796340.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

和PLC对配置的繁琐工序

上位机开发最烦和PLC对轴的位置,点的位置,一大堆的手写工序,数据不是放在Excel表,就是放在txt或者ini 图1.图2这次的需求 我需要手动将图1的数据写到图2 太麻烦 所以我准备写一个工具实现它 首先,我打算生成图2,需要使用到XML反序列化,读取图1,我使用MiniExcel 所以我先…

Redis入门 - C#|.NET Core封装Nuget包

分享封装Redis C#库并打包成Nuget包的方法,旨在增强代码可测试性、解耦及扩展Redis功能。通过封装Redis客户端库,提供统一接口,便于测试、替换和扩展功能,同时支持依赖注入,简化配置和使用。经过前面章节的学习,可以说大家已经算Redis开发入门了。已经可以去到项目上磨砺…

vue3项目部署到Github

此教程适应于以webpack,vue-cli,vite等脚手架构建的vue项目。当然,vue2和vue3都是可以滴。1. 前提:你的代码库已经提交到Github上 如果没有的话,请到GitHub上新建仓库,并把你本地的项目提交到GitHub上新建的仓库里。 具体方法,可以参考我的博客 Git使用记录 - 持续更新 …

[极客大挑战 2019]LoveSQL 1

启动靶机作者不建议使用sqlmap我们这里就进行手工注入 用万能口令登录 admin or 1 =1# ,详情见上文(https://www.cnblogs.com/m1saka1/p/18411197) 登录成功获得用户名和密码,发现密码并没有卵用,只能换思路利用账号密码的回显页面进行sql注入爆破数据库 由于网站自动转义,…

Go日志管理库zap

一、zap介绍 在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 1.能够将事件记录到文件中,而不是应用程序控制台。 2.日志切割-能够根据文件大小、时间或间隔等来切割日志文件。 3.支持不同的日志级别。例如INFO,DEBUG,ERROR等。 4.能够打印基本信息,…

深度神经网络DNN、RNN、RCNN及多种机器学习金融交易策略研究|附数据代码

全文链接:https://tecdat.cn/?p=37668 原文出处:拓端数据部落公众号 分析师:Aijun Zhang 在当今的金融领域,量化交易正凭借其科学性和高效性逐渐成为主流投资方式之一。随着大数据技术的蓬勃发展,量化交易借助先进的数学模型和计算机分析能力,摒弃了人的主观判断,通过…

第一次个人作业

这个作业属于哪个课程 班级的链接这个作业要求在哪里 作业要求的链接这个作业的目标 实现论文查重算法,并对代码进行性能分析、单元测试,使用PSP表GitHub链接 一、PSP表PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)Planning 计划 15 20Estimate 估…

mybatis exists 中使用代替in关键字

使用场景,in适合数据量小的时候,exists适合数据量大的时候。<if test="torqueRecordPageDTO.vinList != null and torqueRecordPageDTO.vinList.size >0">and exists (select 1 from (<foreach collection="torqueRecordPageDTO.vinList" it…

图与网络——TSP问题精解

旅行商问题(Travelling Salesman Problem, TSP)是组合优化领域中的经典问题之一。TSP的概念最早可以追溯到18世纪,瑞士数学家欧拉在解决柯尼斯堡七桥问题时首次提出了关于图中遍历的问题。不过,作为一个优化问题,TSP在19世纪才开始形成系统的研究。1920年代,TSP被德国数学…

[NLP/AIGC] 大语言模型:零一万物

1 概述:零一万物 - 首款开源中英双语大模型 公司背景公司名称:零一万物(01.AI) 创始人:李开复博士(知名投资人、创新工场董事长兼CEO)产品介绍产品名称:Yi 系列大模型Yi-6B:数据参数量为60亿的双语(英文/中文)开源模型 Yi-34B:数据参数量为340亿的双语(英文/中文)…

jackson 原生反序列化触发 getter 方法

jackson 原生反序列化触发 getter 方法jackson的POJONode方法可以任意调用getterjackson序列化会任意调用getter分析 jackson 序列化会调用任意 getter 方法,jackson 反序列化也会任意调用 getter ,这两个都不需要多说什么了,在前面的 jackson 反序列化中的 TemplatesImpl 链…

urllib发送get请求_中文传参问题

GET请求是HTTP协议中的一种基本方法,当需要在GET请求中传递中文参数时需要额外对中文进行编码(英文不需要),因为url中只能包含ascii字符。 可以使用urllib.parser.urlencode()或urllib.parse.quote()方法对中文转码。 详细查官方文档: https://docs.python.org/3.12/libra…