【软工作业2】个人项目-论文查重
| 软件工程 | 计科21级34班 |
|---|---|
| 作业要求 | 软工作业2 |
| 作业目标 | 论文查重、模块设计分析、代码性能改进、单元测试、异常处理、掌握PSP表格的使用 |
Github作业链接
https://github.com/WILLFLWSY/WILLFLWSY/tree/main
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
实现流程设计框架

PSP表格
| PSP2.1* | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 60 |
| · Estimate | · 估计这个任务需要多少时间 | 120 | 120 |
| Development | 开发 | 60 | 60 |
| · Analysis | · 需求分析 (包括学习新技术) | 120 | 120 |
| · Design Spec | · 生成设计文档 | 10 | 15 |
| · Design Review | · 设计复审 | 10 | 15 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
| · Design | · 具体设计 | 20 | 18 |
| · Coding | · 具体编码 | 70 | 70 |
| · Code Review | · 代码复审 | 10 | 6 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 40 | 40 |
| Reporting | 报告 | 60 | 50 |
| · Test Repor | · 测试报告 | 10 | 10 |
| · Size Measurement | · 计算工作量 | 8 | 8 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 8 |
| · 合计 | 508 | 630 | 630 |
| · Size Measurement | · 计算工作量 | 8 | 8 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 8 |
| · 合计 | 508 | 630 | 630 |
模块接口的设计与实现过程
- 函数调用关系

- 算法实现函数-读取文档
//对文章进行分段处理函数
public static String[] getTxt(File file,int num,String[] pages) throws IOException {
int i=0;
String encoding = "utf-8";
//创建读文件对象
try (InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);
BufferedReader bufferedReader = new BufferedReader(read)) {
//用于记录每一行的内容
String lineTxt;
while ((lineTxt = bufferedReader.readLine()) != null) {
pages[i]=lineTxt;
i++;
}
}catch (Exception e) {
writeTxt("读取文件内容出错","","", 2);
}
return pages;
}
- 算法实现函数-原文拆分
//对没个段落进行分句处理函数
public static String[][] getLine(String[] page,String[][] lines) {
int num=0;//记录该句子为该段落中的第几句
for(String p : page) {
String[] temp= {};
temp=p.split(",|\\.|\\?|,|。|?|!");
lines[num]=temp;
num++;
}
return lines;
}
//对文章进行分段处理函数
public static String[] getTxt(File file,int num,String[] pages) throws IOException {
int i=0;
String encoding = "utf-8";
//创建读文件对象
try (InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);
BufferedReader bufferedReader = new BufferedReader(read)) {
//用于记录每一行的内容
String lineTxt;
while ((lineTxt = bufferedReader.readLine()) != null) {
pages[i]=lineTxt;
i++;
}
}catch (Exception e) {
writeTxt("读取文件内容出错","","", 2);
}
return pages;
}
对比的基本思想是按小句进行比较,所以拆分是以标点,即,。?!等进行拆分。
拆分完成以后,可以有很多的小段。本文中为了便于定位,先根据原始段落进行拆分,然后再将每段根据标点拆分成若干小句。
即一个word文档 = [[段落1], [段落2], [段落3], ...,[段落n]],而每个段落= [[小句1],[小句2],[小句3],...,[小句m],]。
如此循环对比输出。
- 算法实现函数-文本对比
//比对函数
public static int compareTxt(String page1,String page2,String[] lines1,String[] lines2) throws IOException {
int num=0;//记录重复字段的字符数
//段落字符数对比
if(page1.length()<=10||page2.length()<10) {
return 0;
}
//逐句对比
for(String line1:lines1) {
for(String line2:lines2) {
if(line1.indexOf(line2)!=-1) {
writeTxt(line2,"","",2);
num+=line2.length();
}else if(line2.indexOf(line1)!=-1) {
writeTxt(line1,"","",2);
num+=line1.length();
}
}
}
return num;
}
根据段落,两两进行对比,遇到匹配输出结果。
综上,各基本函数的调用关系:

模块接口部分的性能改进
- 性能分析
各模块内存占比:

总用时:

模块部分单元测试展示
- 单元测试功能实现函数
public static void main(String[] args) throws IOException {
//获取文件地址
File[] file=new File[2];
file[0]=new File("copy.txt");
file[1]=new File("papers.txt");
writeTxt("------开始对比------","","",1);
String[][] pages=new String[2][];//存储每一段的内容
String[][][] lines=new String[2][][];//存储每一句的内容
int[] chars=new int[2];//存储每篇文章的字符数
//对每篇文章进行比较准备
for(int i=0;i<2;i++) {
//判断文件是否获取成功并获取文章段落数
int pagesNum=isFind(file[i]);
//将每个段落读出并存储起来
String[] page=new String[pagesNum];
page=getTxt(file[i],pagesNum,page);
pages[i]=page;
//将段落划分为句
String[][] line=new String[pagesNum][];
line=getLine(pages[i],line);
lines[i]=line;
//展示文章信息并统计字符数量
chars[i]=showData(lines[i]);
}
//开始对比文章,查找重复内容
writeTxt("------搜索到的重复内容------","","",2);
int cou=0;//记录重复内容的总字符数
if(lines[0].length>lines[1].length) {
for(int i=0;i<lines[0].length;i++) {
for(int j=0;j<lines[1].length;j++) {
cou+=compareTxt(pages[0][i],pages[1][j],lines[0][i],lines[1][j]);
}
}
}else {
for(int i=0;i<lines[1].length;i++) {
for(int j=0;j<lines[0].length;j++) {
cou+=compareTxt(pages[1][i],pages[0][j],lines[1][i],lines[0][j]);
}
}
}
//查找结果的统计处理
float rat;//用于记录查重率
//判断哪篇文章的字符数最少
if(chars[0]<chars[1]) {
rat=(float)cou/chars[0];
}else {
rat=(float)cou/chars[1];
}
//输出结果
writeTxt("------最终的查重结果------","","",2);
String str="该文章相同字符比为:"+rat;
writeTxt(str,"","",2);
}
- 单元测试结果展示
结果文件:

输出相同字符比:
1、测试用例:活着前言(orig.txt、orig_0.8_add.txt)

2、测试用例:活着前言(orig.txt、orig_0.8_del.txt)

3、测试用例:活着前言(orig.txt、orig_0.8_dis_1.txt)

4、测试用例:活着前言(orig.txt、orig_0.8_dis_10.txt)

5、测试用例:活着前言(orig.txt、orig_0.8_dis_15.txt)

6、测试用例:气候变化

代码覆盖率:

模块部分异常处理说明
- 异常情况其一:

原因分析:

解决方法:

- 异常情况其二:

原因分析:

解决方法:

总结
本个人项目为论文查重系统,要求包括熟悉并掌握PSP表格的填写、具象化呈现模块的设计与实现过程、功能分析与性能改进、单元测试以及异常分析与处理等多项指标,既考察了我编写程序能力,又考察了我对软件工程课程的学习与知识的掌握程度。
通过学习并熟悉了本次项目的开发流程,从设计到最终落实,并逐步了解PSP表格的使用,我都受益匪浅。

浙公网安备 33010602011771号