第一次编程作业
目录
项目概述
0. Gitcode链接
1.PSP表格
2.题目描述
3.算法实现基本思路
4.模块接口部分
5.代码实现
6.单元测试示例
项目概述
| 这个项目属于哪个课程 | 软件工程 |
|---|---|
| 作业要求 | 论文查重 |
| 作业的目标 | 学习使用PSP表格,学习commit规范 |
| 参考文献 | 《SimHash算法原理》、《查重算法》 |
- Gitcode链接
https://i.cnblogs.com/posts/edit
1.PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际用时 |
|---|---|---|---|
| Planning | 计划 | 90 | 90 |
| Estimate · | 估计这个任务需要多少时间 | 45 | 60 |
| Development | 开发 | 120 | 150 |
| · Analysis | · 需求分析 (包括学习新技术) | 60 | 60 |
| Design Spec · | 生成设计文档 | 60 | 60 |
| Design Review · | 设计复审 | 60 | 60 |
| Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
| · Design | · 具体设计 | 60 | 60 |
| Coding · | 具体编码 | 30 | 30 |
| Code Review | · 代码复审 | 30 | 30 |
| Test | 测试(自我测试,修改代码,提交修改) | 180 | 150 |
| Reporting | 报告 | 60 | 60 |
| Test Repor | · 测试报告 | 60 | 60 |
| Size Measurement | · 计算工作量 | 10 | 10 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
| ---- | 合计 | 955 | 970 |
2.题目描述
2.题目描述
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
3.算法实现基本思路


4.模块接口部分
| 类名 | 实现方法 |
|---|---|
| MainText(查重主程序类) | main方法 |
| MyException(异常处理类) | cast(异常抛出方法) |
| HammingUtils(海明距离模块工具类) | getHammingDistance(计算海明距离)、getSimilarity(输出相似度) |
| SimHashUtils(SimHash模块工具类) | getHash(计算哈希值)、getSimHash(计算simHash值) |
| TxtIOUtils(txt文件读写工具类) | readTxt(读取txt文本内容)、writeTxt(向txt文件输出文本) |
5.代码实现
`import jieba
import re
from collections import Counter
import sys
预编译正则表达式以提高效率
PUNCTUATION_PATTERN = re.compile(r'[^\u4e00-\u9fa5a-zA-Z0-9]')
def preprocess(text):
"""预处理文本,去除标点符号和特殊字符"""
return PUNCTUATION_PATTERN.sub('', text)
def read_file(file_path):
"""读取文件内容"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
print(f"错误:文件 {file_path} 未找到。")
sys.exit(1)
except Exception as e:
print(f"读取文件时发生错误:{e}")
sys.exit(1)
def calculate_similarity(orig_text, copy_text):
"""计算两段文本的余弦相似度"""
orig_processed = preprocess(orig_text)
copy_processed = preprocess(copy_text)
# 分词
orig_words = jieba.lcut(orig_processed)
copy_words = jieba.lcut(copy_processed)
# 统计词频
vec1 = Counter(orig_words)
vec2 = Counter(copy_words)
# 所有唯一词
all_words = set(vec1.keys()) | set(vec2.keys())
# 计算点积和模长
dot_product = sum(vec1.get(word, 0) * vec2.get(word, 0) for word in all_words)
norm1 = sum(v ** 2 for v in vec1.values()) ** 0.5
norm2 = sum(v ** 2 for v in vec2.values()) ** 0.5
if norm1 * norm2 == 0:
return 0.0
return dot_product / (norm1 * norm2)
def main():
if len(sys.argv) != 4:
print("用法: python main.py [原文文件] [抄袭版文件] [答案文件]")
sys.exit(1)
orig_path, copy_path, ans_path = sys.argv[1], sys.argv[2], sys.argv[3]
orig_text = read_file(orig_path)
copy_text = read_file(copy_path)
similarity = calculate_similarity(orig_text, copy_text)
result = round(similarity * 100, 2)
try:
with open(ans_path, 'w', encoding='utf-8') as f:
f.write(f"{result:.2f}")
except Exception as e:
print(f"写入答案文件时发生错误:{e}")
sys.exit(1)
if name == "main":
main()`
6.单元测试示例
`import unittest
from main import calculate_similarity
import math
class TestPlagiarismChecker(unittest.TestCase):
def test_identical_texts(self):
orig = "今天是星期天,天气晴,今天晚上我要去看电影。"
copy = orig
self.assertAlmostEqual(calculate_similarity(orig, copy), 1.0, places=2)
def test_no_common_words(self):
orig = "今天天气晴朗"
copy = "明天会下雨"
self.assertAlmostEqual(calculate_similarity(orig, copy), 0.0, places=2)
def test_partial_overlap(self):
orig = "中国美国"
copy = "中国日本"
expected = 1 / (math.sqrt(2) * math.sqrt(2))
self.assertAlmostEqual(calculate_similarity(orig, copy), expected, places=2)
def test_empty_original(self):
orig = ""
copy = "测试文本"
self.assertAlmostEqual(calculate_similarity(orig, copy), 0.0, places=2)
if name == 'main':
unittest.main()`
浙公网安备 33010602011771号