个人项目作业-论文查重
|这个课程属于哪个课程 | 软件工程2024-双学位 (广东工业大学)|第二次作业
|-- |-- |
|这个作业要求在哪里 |个人项目作业-论文查重 |
|这个作业的目标 |代码实现、性能分析、单元测试、异常处理说明、记录PSP表格 |
本项目已上传到Gitcode
需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例(提取码:nwjr),使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位。
开发环境
| 编程语言 | Python |
|---|---|
| IDE | PyCharm Community Edition 2023.3.4 |
| Python版本 | 3.10.11 |
依赖库
- coverage == 7.4.3
- jieba == 0.42.1
- line-profiler == 4.1.2
- line-profiler-pycharm == 1.1.0
- numpy == 1.26.4
代码实现
接口设计
jieba分词
def tokenize(stopwords_file, text):
stopwords = set()
with open(stopwords_file, 'r', encoding='utf-8') as file:
stopwords = set(line.strip() for line in file.readlines())
words = jieba.cut(text) # 使用jieba库的cut接口分词进行分词
return [word for word in words if word.strip() and word not in stopwords]
文本转换为词向量
def count_words(tokens, total_unique_words):
word_counts = Counter(tokens)
vector = [word_counts.get(word, 0) for word in total_unique_words]
return vector
numpy计算余弦相似度
def cosine_similarity(vec1, vec2):
dot_product = np.dot(vec1, vec2)
norm_vec1 = np.linalg.norm(vec1)
norm_vec2 = np.linalg.norm(vec2)
return dot_product / (norm_vec1 * norm_vec2)
命令行参数
parser = argparse.ArgumentParser()
parser.add_argument('source_file', help='原文文件的绝对路径')
parser.add_argument('target_file', help='抄袭版本文件的绝对路径')
parser.add_argument('res_file', help='输出答案文件的绝对路径')
args = parser.parse_args()
main函数
def main(args):
stopwords_file = 'test_stopwords.txt'
with open(args.source_file, 'r', encoding='utf-8') as f:
source_text = f.read()
with open(args.target_file, 'r', encoding='utf-8') as f:
target_text = f.read()
# 对原文和抄袭版本文本进行分词处理
source_tokens = tokenize(stopwords_file, source_text)
target_tokens = tokenize(stopwords_file, target_text)
# 获取总词汇表
total_words = list(set(source_tokens + target_tokens))
# 将分词后的文本转换为词向量
source_vector = count_words(source_tokens, total_words)
target_vector = count_words(target_tokens, total_words)
# 计算余弦相似度
similarity = cosine_similarity(source_vector, target_vector)
similarity_percentage = similarity * 100
with open(args.res_file, 'w', encoding='utf-8') as f:
f.write('相似度为:%.2f%%' % similarity_percentage)
执行结果

单元测试
导入unittest模块,编写测试单元。
被测试函数:
- tokenize
- count_words
- cosine_similarity
import unittest
from main import tokenize, count_words, cosine_similarity
class TestTextSimilarity(unittest.TestCase):
def test_tokenize(self):
# 测试 tokenize 函数
stopwords_file = 'test_stopwords.txt'
text_with_stopwords = "这是一个测试文本"
expected_tokens_with_stopwords = ['这是', '一个', '测试', '文本']
tokens_with_stopwords = tokenize(stopwords_file, text_with_stopwords)
# 验证每个标记是否正确
self.assertEqual(tokens_with_stopwords[0], expected_tokens_with_stopwords[0])
self.assertEqual(tokens_with_stopwords[1], expected_tokens_with_stopwords[1])
self.assertEqual(tokens_with_stopwords[2], expected_tokens_with_stopwords[2])
self.assertEqual(tokens_with_stopwords[3], expected_tokens_with_stopwords[3])
def test_count_words(self):
# 测试 count_words 函数
tokens = ['a', 'b', 'a', 'c']
total_unique_words = ['a', 'b', 'c', 'd']
expected_vector = [2, 1, 1, 0]
vector = count_words(tokens, total_unique_words)
self.assertEqual(vector, expected_vector)
def test_cosine_similarity(self):
# 测试 cosine_similarity 函数
vec1 = [1, 2, 3]
vec2 = [2, 3, 4]
expected_similarity = 0.9925833339709303
similarity = cosine_similarity(vec1, vec2)
self.assertAlmostEqual(similarity, expected_similarity, places=4)
if __name__ == '__main__':
unittest.main()
代码性能
性能分析
利用python的cProfile库对其进行性能分析。

代码覆盖率
利用coverage工具实现覆盖率测试。
通过命令
coverage run main.py
生成测试文件。



可以看出test.py的代码覆盖率为百分之百,但main.py的代码覆盖率只有52%,我们检查下原因。

可以看出是因为我们的main函数依赖命令行输入文件地址才可以运行,不影响其性能。
PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 20 | 30 |
| Estimate | 估计这个任务需要多少时间 | 30 | 20 |
| Development | 开发 | 80 | 100 |
| Analysis | 需求分析 (包括学习新技术) | 120 | 150 |
| Design Spec | 生成设计文档 | 30 | 30 |
| Design Review | 设计复审 | 20 | 20 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
| Design | 具体设计 | 30 | 30 |
| Coding | 具体编码 | 90 | 120 |
| Code Review | 代码复审 | 30 | 20 |
| Test | 测试(自我测试,修改代码,提交修改) | 80 | 100 |
| Reporting | 报告 | 100 | 80 |
| Test Repor | 测试报告 | 100 | 90 |
| Size Measurement | 计算工作量 | 30 | 30 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
| 合计 | 810 | 850 |

浙公网安备 33010602011771号