Github:https://github.com/ywx1207/ywx1207
| 这个作业属于哪个课程 | 工程概论 |
|---|---|
| 作业要求在哪里 | https://edu.cnblogs.com/campus/jmu/ComputerScience21/homework/13034 |
| 作业目标 | Github项目管理,熟悉项目开发过程 |
作业需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟 | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 5 | 5 |
| ·Estimate | .估计这个任务需要多少时间 | 180 | 230 |
| Development | 开发 | 15 | 20 |
| .Analysis | .需求分析(包括学习新技术) | 60 | 160 |
| .Design Spec | .生成设计文档 | 30 | 30 |
| .Design Review | .设计复审 | 5 | 5 |
| .Coding Standard | .代码规范(为目前的开发指定合适的规范) | 5 | 5 |
| .Design | .具体设计 | 30 | 20 |
| .Coding | .具体编码 | 60 | 115 |
| .Code Review | .代码复审 | 30 | 120 |
| .Test | .测试(自我测试,修改代码,提交修改) | 20 | 120 |
| Reporting | 报告 | 60 | 150 |
| .Test Report | .测试报告 | 45 | 45 |
| .Size Measurement | .计算工作量 | 5 | 5 |
| .Postmortem & Process Improvement Plan | .事后总结,并提出改进计划 | 0 | 0 |
| .合计 | 550 | 610 | 1030 |
开发环境
语言:java 14
工具:IDEA 2020
系统:Windows 11
算法设计
算法思路
1.读入两篇文章并转化为字符串
2.使用正则表达式匹配并去除文章标点符号
3.使用中文分词库HanLP进行文本分词
4.使用余弦相似度算法统计词频并计算出相似度
5.将结果写入目标文件
函数
| 函数 | 作用 |
|---|---|
| calculateSimHash | 计算SimHash值 |
| calculateHammingDistance | 计算海明距离 |
| hash | 哈希函数 |
| readTextFromFile | 从txt文件中读取内容 |
流程图

性能分析

单元测试



异常处理
读取文件可能会出现IO异常

结果

点击查看代码
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
public class PlagiarismChecker {
private static final int HASH_SIZE = 64; // SimHash的哈希位数
private static final int SIMILARITY_THRESHOLD = 10; // 相似度阈值
// 计算SimHash值
private static long calculateSimHash(String text) {
int[] hashBits = new int[HASH_SIZE];
// 分词处理
String[] words = text.split("\\s+");
// 生成哈希值
for (String word : words) {
long wordHash = hash(word);
for (int i = 0; i < HASH_SIZE; i++) {
long bitmask = 1L << i;
if ((wordHash & bitmask) != 0) {
hashBits[i] += 1;
} else {
hashBits[i] -= 1;
}
}
}
// 构造SimHash值
long simHash = 0;
for (int i = 0; i < HASH_SIZE; i++) {
if (hashBits[i] >= 0) {
simHash |= 1L << i;
}
}
return simHash;
}
// 计算海明距离
private static int calculateHammingDistance(long hash1, long hash2) {
long xor = hash1 ^ hash2;
int distance = 0;
while (xor != 0) {
distance += 1;
xor &= xor - 1;
}
return distance;
}
// 哈希函数
private static long hash(String word) {
// 在实际应用中,可以使用更复杂的哈希函数
return word.hashCode();
}
// 从txt文件中读取内容
private static String readTextFromFile(String filePath) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
}
public static void main(String[] args) {
String file1 = "E:\\JavaProject\\untitled2\\orig.txt";
String file2 = "E:\\\\JavaProject\\\\untitled2\\\\orig_add.txt";
String answerFile = "E:\\\\JavaProject\\\\untitled2\\\\answer.txt";
try {
// 从文件中读取论文内容
String paper1 = readTextFromFile(file1);
String paper2 = readTextFromFile(file2);
// 计算SimHash值
long hash1 = calculateSimHash(paper1);
long hash2 = calculateSimHash(paper2);
// 计算海明距离
int distance = calculateHammingDistance(hash1, hash2);
// 计算重复率
double similarity = 1.0 - (double) distance / HASH_SIZE;
// 折算成百分制并保留小数点后两位
double similarityPercentage = similarity * 100;
DecimalFormat decimalFormat = new DecimalFormat("0.00");
String formattedSimilarity = decimalFormat.format(similarityPercentage);
// 输出结果到答案文件
try (PrintWriter writer = new PrintWriter(new FileWriter(answerFile))) {
writer.println("Paper 1: " + paper1);
writer.println("Paper 2: " + paper2);
writer.println("相似度: " + formattedSimilarity + "%");
}
System.out.println("Plagiarism check completed. Results written to " + answerFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}