软工第二次作业——个人项目
这个作业属于哪个课程 | 个人项目 |
---|---|
这个作业要求在哪里 | 个人项目 |
这个作业的目标 | 利用GitHub平台存储历史代码,对程序各模块做单元测试 |
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
Estimate | 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 200 | 200 |
Analysis | 需求分析 (包括学习新技术) | 80 | 200 |
Design Spec | 生成设计文档 | 40 | 10 |
Design Review | 设计复审 | 20 | 10 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 10 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 100 | 100 |
Code Review | 代码复审 | 20 | 20 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 300 |
Reporting | 报告 | 50 | 100 |
Test Repor | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 750 | 1110 |
开发环境
- 开发语言:Java
- 编译器:IDEA 2022.1
项目结构以及核心代码说明
1.org.yby.core.util这个包下存放用到的工具类,AlgorithmUtils是算法的核心实现部分,FileHandUtils是处理文件工具类,TextUtils用来处理文字,MathUtils是一些数学计算工具类;
2.org.yby.core.test这个包下存放的是单元测试;
3.Main这个类是程序入口。
算法实现部分
/**
* 这个类用来设计查重算法需要用到的算法
*/
public final class AlgorithmUtils {
//工具类
private AlgorithmUtils(){}
/**
* 匹配两个字符串的匹配程度
* @param checked 被匹配字符串
* @param target 目标匹配字符串
* @return 两个字符串的匹配程度
*/
public static float fuzzyMatch(String target,String checked){
/* 算法过程 权重取[0.2 0.7 0.1]
1.统计两个字符相同字数的数量占据target的百分比
2.统计连续相同的字符数量(字符数>=2)占据target的百分比
3.比较两个字符的长度,如果长度差越大,那么两个字符串一致的概率越小
*/
int targetLen = target.length();
int checkedLen = checked.length();
//System.out.println("target总长度:"+targetLen+" checked总长度:"+checkedLen);
float[] items = new float[3];
//统计item1
for (int i = 0; i < targetLen; i++) {
for (int j = 0; j < checkedLen; j++) {
if(target.charAt(i) == checked.charAt(j)){
items[0]++;
break;
}
}
}
//System.out.println("相同字的数量:"+items[0]);
items[0] = items[0] / targetLen;
//统计item2
items[1] = findAllTheSameStrLength(target,checked);
//System.out.println("相同词组的数量:"+items[1]);
items[1] = items[1] / targetLen;
//统计item3
items[2] = Math.abs(targetLen - checkedLen) / (float)targetLen;
//标准化
// MathUtils.standardization(items);
// MathUtils.normalization(items);
// System.out.println(Arrays.toString(items));
float rt = items[0] * 0.4f + items[1] * 0.6f - items[2]*0.1f;
return rt<0 ? 0.001f : rt>1 ? 0.99f : rt;
}
/**
* 找出str1与str2所有完全一样的字符子串(每个子串不能再含有子串)
* @return 字符子串数量的总长度
*/
public static int findAllTheSameStrLength(String str1, String str2){
String max = str1.length()>str2.length() ? str1 : str2;
String min = max.equals(str1) ? str2 : str1;
int minIdx=0,maxIdx=0,result=0;
while (minIdx<min.length()){
int temp = minIdx;
if(minIdx+1<min.length() && maxIdx+1<max.length() && min.charAt(minIdx) == max.charAt(maxIdx) && min.charAt(minIdx+1) == max.charAt(maxIdx+1)){
maxIdx+=2; minIdx+=2;
while (minIdx<min.length() && maxIdx<max.length() && min.charAt(minIdx) == max.charAt(maxIdx)){
maxIdx++;minIdx++;
}
}
if(minIdx!=temp){
result+=minIdx-temp;
}
if(++maxIdx > max.length()){maxIdx=minIdx;minIdx++;}
}
return result;
}
}
文件处理
package org.yby.core.utils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* 文件处理工具
*/
public final class FileHandUtils {
private FileHandUtils(){}
public static List<String> readAllLine(String path){
List<String> strs = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line;
while ((line = reader.readLine()) != null) {
if(!checkAllNull(line)){ //跳过空行
//System.out.println(line);
strs.add(line.trim());
}
}
} catch (IOException e) {
System.out.println("你输入的文件路径不正确!");
return null;
}
return strs;
}
/**
* 将一个文章按句子分开
* @param path 文件路径
* @return 所有句子
*/
public static String readAllSentence(String path){
List<String> list = readAllLine(path);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Objects.requireNonNull(list).size(); i++) {
sb.append(list.get(i));
}
return sb.toString();
}
public static void write(String content,String path){
try {
// 创建 FileWriter 对象
FileWriter fileWriter = new FileWriter(path);
// 创建 BufferedWriter 对象
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
// 将字符串写入文件
bufferedWriter.write(content);
// 关闭 BufferedWriter
bufferedWriter.close();
} catch (IOException e) {
System.out.println("文件路径错误!");
}
}
/**
* 检查一个字符串是不是全部是空格
*/
public static boolean checkAllNull(String str){
return Pattern.matches("^\\s*$", str);
}
}
单元测试
package org.yby.core.test;
import org.yby.core.utils.AlgorithmUtils;
import org.yby.core.utils.FileHandUtils;
import org.yby.core.utils.MathUtils;
import org.yby.core.utils.TextUtils;
import java.util.HashMap;
/**
* 测试算法的可行性
*/
public class AlgorithmTest {
//测试案例
private static final HashMap<String,String> DEMOS = new HashMap<>();
private static final String originTxtPath = "D:\\Programmings\\IDEA_Programming\\PracticeProjects\\SoftwareHomework\\src\\main\\resources\\orig.txt";
private static final String testTxtPath = "D:\\Programmings\\IDEA_Programming\\PracticeProjects\\SoftwareHomework\\src\\main\\resources\\orig_0.8_add.txt";
private static final String outPutPath = "F:\\Temp\\ans.txt";
private static void initData(){
DEMOS.put(
"认真对待每一天,因为它不会再回来。勇气不是没有恐惧,而是战胜了恐惧。",
"认真对待每一天,因为它会再回来。勇气不是没有恐惧,不是战胜了恐惧。");
DEMOS.put("活出自己的生命,而不是活成别人的模样。",
"活出自己生命,活成别人的模样。");
DEMOS.put("好事不必做准备,来了就来了,最多是个喜出望外。享用谁还不会;可对坏事总无思想准备,一旦突如其来,就会措手不及,天塌地陷。",
"好事不必做准备,来了就来了,是个喜出望外。可对坏事总无思想准备,一旦突如其来,就会措手不及,天塌地陷。");
DEMOS.put("夜幕降临,星星点点布满了夜空,月亮悄然升起,洒下一片温柔的光芒,照亮了整个夜晚。",
"夜幕降临,星光闪烁,夜空璀璨夺目,皓月缓缓升起,洒下柔和光芒,照亮了整个夜晚。");
DEMOS.put("这时野地里最热闹的,莫过于那些伶俐矫健的小麻雀了。",
"这时野地里最不热闹的,莫过于那些伶俐矫健的大麻雀了吧。");
DEMOS.put("日子总是像从指尖渡过的细纱,在不经意间悄然滑落。那些往日的忧愁和误用伤,在似水流年的荡涤下随波轻轻地逝去。",
"日子总是像从指尖渡过的细纱,在不经意间悄然滑落,在似水流年的荡涤下随波轻轻地逝去。");
DEMOS.put("人生中最大的乐趣是奉献;思维中最美的花朵是智慧之花;前进中最快的脚步是继续;朋友中最好的记忆是笑声!",
"人生中最大的乐趣是奉献;思维中最美的花朵是智慧之花;可是,小心啊,切勿让其变幻了你评判的目光。");
DEMOS.put("未来的东西就是这样:当你墨守成规时,它永远与你的昨天一样;当你积极进取时,就会化作灿烂无比的春光。",
"未来的东西就是这样:当你积极进取时,就会化作灿烂无比的春光;当你墨守成规时,它永远与你的昨天一样。");
DEMOS.put("人生中最艰难的是选择;工作中最困难的是创新;生活中最痛苦的是自扰;做人中最苦恼的是委屈。",
"生活中最痛苦的是自扰;做人中最苦恼的是委屈;人生中最艰难的是选择;工作中最困难的是创新。");
DEMOS.put("柔和的阳光斜挂在苍松翠柏不凋的枝叶上,显得那么安静肃穆",
"柔和的阳光斜挂在苍松翠柏不凋的枝叶上,显得那么冷清高雅");
DEMOS.put("重重叠叠的高山,看不见一个村庄,看不见一块稻田",
"重重叠叠的高山,看不见一个村庄和一块稻田");
}
public static void test1(){
initData();
System.out.println(" 正向检查 反向检查 ");
DEMOS.forEach((k,v)->{
String target = TextUtils.getFullCharacter(k);
String checked = TextUtils.getFullCharacter(v);
System.out.println(" "+AlgorithmUtils.fuzzyMatch(target,checked)+" "+AlgorithmUtils.fuzzyMatch(checked,target));
});
}
public static void test2(){
String target = TextUtils.getFullCharacter(FileHandUtils.readAllSentence(originTxtPath));
String checked = TextUtils.getFullCharacter(FileHandUtils.readAllSentence(testTxtPath));
float rt = AlgorithmUtils.fuzzyMatch(target, checked);
FileHandUtils.write(Float.toString(rt),outPutPath);
System.out.println(rt);
System.out.println(MathUtils.keep2b(rt));
}
}
Github仓库链接:https://github.com/su-qing-yi/3222004337.git