第二次作業--論文查重

珺勋發表於2024-03-14
這個作業屬於哪個課程 軟體工程
這個作業要求在哪裡 個人專案
這個作業的目標 完成個人專案,運用psp流程完成程式設計, 靈活使用測試工具和效能分析工具

專案GetHub

PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 30
Estimate 估計這個任務需要多少時間 10 10
Development 開發 900 600
Analysis 需求分析 (包括學習新技術) 30 60
Design Spec 生成設計文件 30 30
Design Review 設計複審 10 10
Coding Standard 程式碼規範 (為目前的開發制定合適的規範) 20 20
Design 具體設計 60 50
Coding 具體編碼 300 400
Code Review 程式碼複審 20 20
Test 測試(自我測試,修改程式碼,提交修改) 60 60
Reporting 報告 60 60
Test Repor 測試報告 60 60
Size Measurement 計算工作量 20 20
Postmortem & Process Improvement Plan 事後總結, 並提出過程改進計劃 50 50
合計 1770 1460

計算模組介面的實現
1.simhash核心演算法介紹
2.透過idea底層原碼,利用java輸入輸出流引入文字物件
3.將文字中的文字轉換為字串,利用simhash演算法,逐個獲取雜湊值,漢明距離以及特徵值
計算模組介面部分的效能改進
1.效能圖
方法呼叫情況


2.CPU使用情況

3.覆蓋率

計算模組部分單元測試展示
1.主模組測試

點選檢視程式碼
package 部落格;

import java.text.Format;

public class test {
    public static void main(String[] args) {
        String origin="E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig.txt";
        String[] s={"E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig_0.8_add.txt",
                "E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig_0.8_del.txt",
                "E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig_0.8_dis_1.txt",
                "E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig_0.8_dis_10.txt",
                "E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig_0.8_dis_15.txt"};
        FileInput fileInput = new FileInput();
        SimHashImpl hash1 = new SimHashImpl(fileInput.readString(origin), 64);
        hash1.subByDistance(hash1, 3);
//        測試文件1
        addTestOne(origin,s,fileInput,hash1);
//        測試文件2
        addTestTwo(origin,s,fileInput,hash1);
//        測試文件3
        addTestThree(origin,s,fileInput,hash1);
//        測試文件4
        addTestFour(origin,s,fileInput,hash1);
//        測試文件5
        addTestFive(origin,s,fileInput,hash1);
//        文件路徑不存在
        addError(origin,s,fileInput,hash1);
    }

    private static void addError(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString("orig.txt"), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }

    private static void addTestFive(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString(s[4]), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }

    private static void addTestFour(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString(s[3]), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }

    private static void addTestThree(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString(s[2]), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }

    private static void addTestTwo(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString(s[1]), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }

    private static void addTestOne(String origin, String[] s, FileInput fileInput, SimHashImpl hash1) {
        SimHashImpl hash2 = new SimHashImpl(fileInput.readString(s[0]), 64);
        hash2.subByDistance(hash2, 3);
        double distance = hash1.getDistance(hash1.getStrSimHash(),hash2.getStrSimHash());
        System.out.println("該文章與原文相似度為:"+String.format("%.2f",(100-distance*100/128)) +"%");
    }
}

2.讀寫檔案模組測試
點選檢視程式碼
package 部落格;

import java.io.*;

public class FileInput {
    public String readString(String FI){
        int len=0;
//        對字串進行多次修改,並且不會產生新的未產生的使用物件
//        建立一個
        StringBuffer str=new StringBuffer("");
//        File類以抽象類的方式代表檔名和目錄路徑名,用於檔案和目錄的建立,查詢和刪除
//        FI代表需要插入檔案的目錄
//        file獲取傳過來的路徑名,獲取檔案物件
        File file = new File(FI);
//     try{}當中利用readline來讀取檔案中的內容
        try {
//            FileInputStream()用於從檔案中讀取資料,他的物件用關鍵字new來建立
//            也可以使用一個檔案物件來建立一個輸入流隊形物件來讀取檔案
//             File f=new File("C:/java/hello");
//            InputStream in =new FileInputStream(f);
            FileInputStream fileInputStream = new FileInputStream(file);
//            將讀取檔案中的內容賦給物件bufferedReader
//            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line=null;
//            bufferedReader.readLine()從文字物件中讀取一行資料,見名知意,就是一行一行讀取
            while((line=bufferedReader.readLine())!=null){
                if (len!=0){
//                    除了第一行,每一行都需要換行,str為StringBuffer類,多次新增資料
                    str.append("\r\n"+line);
//                    str.append(line);
                }else {
                    str.append(line);
                }
                len++;
            }
//            System.out.println(len);
//            關閉此檔案輸入流並釋放與此流有關的所有系統資源
            bufferedReader.close();
            fileInputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str.toString();
//        return str;
    }

    public static void main(String[] args) {
//
        FileInput fileInput = new FileInput();
        String s = fileInput.readString("E:\\文件\\WeChat Files\\wxid_my9r0rap70vc22\\FileStorage\\File\\2024-03\\測試文字\\orig.txt");
        System.out.println(s);
    }
}

3.simHash模組測試
點選檢視程式碼
public BigInteger simHash() {
        // 定義特徵向量/陣列
        int[] v = new int[this.hashbits];
        StringTokenizer stringTokens = new StringTokenizer(this.tokens);
        while (stringTokens.hasMoreTokens()) {
            String temp = stringTokens.nextToken();
            //2、將每一個分詞hash為一組固定長度的數列.比如 64bit 的一個整數.
            BigInteger t = this.hash(temp);
            for (int i = 0; i < this.hashbits; i++) {
                BigInteger bitmask = new BigInteger("1").shiftLeft(i);
                // 3、建立一個長度為64的整數陣列(假設要生成64位的數字指紋,也可以是其它數字),
                // 對每一個分詞hash後的數列進行判斷,如果是1000...1,那麼陣列的第一位和末尾一位加1,
                // 中間的62位減一,也就是說,逢1加1,逢0減1.一直到把所有的分詞hash數列全部判斷完畢.
                if (t.and(bitmask).signum() != 0) {
                    v[i] += 1;
                } else {
                    v[i] -= 1;
                }
            }
        }
        BigInteger fingerprint = new BigInteger("0");
        StringBuffer simHashBuffer = new StringBuffer();
        for (int i = 0; i < this.hashbits; i++) {
            // 4、最後對陣列進行判斷,大於0的記為1,小於等於0的記為0,得到一個 64bit 的數字指紋/簽名.
            if (v[i] >= 0) {
                fingerprint = fingerprint.add(new BigInteger("1").shiftLeft(i));
                simHashBuffer.append("1");
            }else{
                simHashBuffer.append("0");
            }
        }
        this.strSimHash = simHashBuffer.toString();
        setStrSimHash(strSimHash);
//        System.out.println(this.strSimHash + " length " + this.strSimHash.length());
        return fingerprint;
    }