個人項目:論文查重

来源:https://www.cnblogs.com/twilight-yang/p/18071670
-Advertisement-
Play Games

這個作業屬於哪個課程 軟體工程2024 這個作業要求在哪裡 個人項目 這個作業的目標 瞭解軟體項目開發的整體流程,實現自己的個人項目,學習單元測試、性能優化和 git 操作,學會使用 PSP 表格 Github地址 : 點擊此處,進入我的倉庫 一、項目需求 題目:論文查重 設計一個論文查重演算法,給出 ...


這個作業屬於哪個課程 軟體工程2024
這個作業要求在哪裡
個人項目
這個作業的目標 瞭解軟體項目開發的整體流程,實現自己的個人項目,學習單元測試、性能優化和 git 操作,學會使用 PSP 表格

 
Github地址點擊此處,進入我的倉庫

一、項目需求

題目:論文查重

設計一個論文查重演算法,給出一個原文文件和一個在這份原文上經過了增刪改的抄襲版論文的文件,在答案文件中輸出其重覆率。
 

  • 原文示例:今天是星期天,天氣晴,今天晚上我要去看電影。

  • 抄襲版示例:今天是周天,天氣晴朗,我晚上要去看電影。

 
要求輸入輸出採用文件輸入輸出,規範如下:

  • 從命令行參數給出:論文原文的文件的絕對路徑。

  • 從命令行參數給出:抄襲版論文的文件的絕對路徑。

  • 從命令行參數給出:輸出的答案文件的絕對路徑。

 
提供的樣例:orig.txt是原文,其他orig_add.txt等均為抄襲版論文。樣例下載地址
 
答案文件中輸出的答案為浮點型,精確到小數點後兩位
 

二、設計和實現

1、整體流程

基本流程

2、類和函數

方法 描述
Main main() 主程式入口
TxtUtils readFile(String filePath)
writeFile(double fileElem, String filePath)
從目標文件路徑中讀取文件內容
將結果寫入指定文件
HashUtils getHash(String str)
getSimHash(String str)
傳入 String ,計算出它的 hash 值,並以字元串形式輸出
傳入 String ,計算出它的 simHash 值
HammingUtils calculateHammingDistance(String simHash1, String simHash2)
calculateSimilarity(String simHash1, String simHash2)
計算兩個 SimHash 值的海明距離
輸入兩個 simHash 值,輸出相似度
ExceptionUtils ExceptionUtils(String message) 處理文本過短異常

3、關鍵演算法

simHash演算法和海明距離實現論文查重

三、性能改進

性能分析圖:
Override性能分析圖
 
Memory占用圖:
Memory占用圖
byte類、String類和HashMap類占用較,byte類、String類主要來自於simHash值和海明距離的計算,HashMap類主要來自於使用分詞器分詞需要用到Map進行詞頻映射,可從此處改進。

四、單元測試

1. 讀寫 txt 文件的模塊測試

思路:測試讀取成功、讀取失敗、寫入成功、寫入失敗的情況

代碼:

public class TxtUtilsTest {
    @Test
    public void readTest() {
        // 路徑存在 讀取成功
        String str = TxtUtils.readFile("D:/test/orig.txt");
        String[] strings = str.split(" ");
        for (String string : strings) {
            System.out.println(string);
        }
    }
    @Test
    public void readTestErr() {
        // 路徑不存在 讀取失敗
        String str = TxtUtils.readFile("D:/test/orig111.txt");
        String[] strings = str.split(" ");
        for (String string : strings) {
            System.out.println(string);
        }
    }
    @Test
    public void writeTest() {
        // 路徑存在 寫入成功
        double[] elem = {0.12, 0.23, 0.34, 0.45, 0.56,0.99,0.88};
        for (double v : elem) {
            TxtUtils.writeFile(v, "D:/test/answer.txt");
        }
    }
    @Test
    public void writeTestErr() {
        //路徑錯誤 寫入失敗
        double[] elem = {0.12, 0.23, 0.34, 0.45, 0.56,0.99,0.88};
        for (double v : elem) {
            TxtUtils.writeFile(v, "QQ:/test//answer.txt");
        }
    }
}

測試結果:

測試結果

代碼覆蓋率:

代碼覆蓋率

 
2. hash 模塊測試

代碼:

public class HashUtilsTest {
    @Test
    public void getHashTest() {
        // 短文本
        String[] strings = {"畫畫" , "多大" , "GG" , "火" , "阿凡達ya" , "版"};
        for (String string : strings) {
            String strHash = HashUtils.getHash(string);
            if (strHash != null) {
                System.out.println(strHash.length());
            }
            System.out.println(strHash);
        }
    }
    @Test
    public void getSimHashTest0() {
        // 短文本
        String str = "好";
        System.out.println(HashUtils.getSimHash(str));
    }
    @Test
    public void getSimHashTest() {
        // 長文本
        String str0 = TxtUtils.readFile("D:/test/orig.txt");
        String str1 = TxtUtils.readFile("D:/test/orig_0.8_add.txt");
        System.out.println(HashUtils.getSimHash(str0));
        System.out.println(HashUtils.getSimHash(str1));
    }
}

測試結果:

測試結果

代碼覆蓋率:

代碼覆蓋率

 
3. 計算海明距離模塊測試

代碼:

public class HammingUtilsTest {
    @Test
    public void hammingDistanceTest0() {
        String str0 = "10101100";
        String str1 = "11001111";
        int distance = HammingUtils.calculateHammingDistance(str0,str1);
        double similarity = HammingUtils.calculateSimilarity(str0,str1);
        System.out.println("海明距離為:" + distance);
        System.out.println("相似度為:" + similarity);
    }
    @Test
    public void hammingDistanceTest1() {
        // 長度不等
        String str0 = "10101100";
        String str1 = "110011";
        int distance = HammingUtils.calculateHammingDistance(str0,str1);
//        double similarity = HammingUtils.calculateSimilarity(str0,str1);
        System.out.println("海明距離為:" + distance);
//        System.out.println("相似度為:" + similarity );
    }
    @Test
    public void hammingDistanceTest2() {
        String str0 = TxtUtils.readFile("D:/test/orig.txt");
        String str1 = TxtUtils.readFile("D:/test/orig_0.8_add.txt");
        int distance = HammingUtils.calculateHammingDistance(Objects.requireNonNull(HashUtils.getSimHash(str0)), Objects.requireNonNull(HashUtils.getSimHash(str1)));
        double similarity = HammingUtils.calculateSimilarity(HashUtils.getSimHash(str0),HashUtils.getSimHash(str1));
        System.out.println("海明距離為:" + distance);
        System.out.println("相似度為:" + similarity);
    }

    @Test
    public void hammingDistanceTest3() {
        String str0 = TxtUtils.readFile("D:/test/orig.txt");
        String str1 = TxtUtils.readFile("D:/test/orig_0.8_del.txt");
        int distance = HammingUtils.calculateHammingDistance(Objects.requireNonNull(HashUtils.getSimHash(str0)), Objects.requireNonNull(HashUtils.getSimHash(str1)));
        double similarity = HammingUtils.calculateSimilarity(HashUtils.getSimHash(str0),HashUtils.getSimHash(str1));
        System.out.println("海明距離為:" + distance);
        System.out.println("相似度為:" + similarity);
    }

    @Test
    public void hammingDistanceTest4() {
        String str0 = TxtUtils.readFile("D:/test/orig.txt");
        String str1 = TxtUtils.readFile("D:/test/orig_0.8_dis_1.txt");
        int distance = HammingUtils.calculateHammingDistance(Objects.requireNonNull(HashUtils.getSimHash(str0)), Objects.requireNonNull(HashUtils.getSimHash(str1)));
        double similarity = HammingUtils.calculateSimilarity(HashUtils.getSimHash(str0),HashUtils.getSimHash(str1));
        System.out.println("海明距離為:" + distance);
        System.out.println("相似度為:" + similarity);
    }
}

測試結果:

測試結果

代碼覆蓋率:

代碼覆蓋率

 

4.主測試 MainTest

代碼:

public class MainTest {
    @Test
    public void mainTestAll() {
        String[] args = new String[6];
        args[0] = "D:/test/orig.txt";
        args[1] = "D:/test/orig_0.8_add.txt";
        args[2] = "D:/test/orig_0.8_del.txt";
        args[3] = "D:/test/orig_0.8_dis_1.txt";
        args[4] = "D:/test/orig_0.8_dis_10.txt";
        args[5] = "D:/test/orig_0.8_dis_15.txt";
        String answerPath = "D:/test/answerAll.txt";
        for (int i=1; i< args.length;i++){
            double answer = HammingUtils.calculateSimilarity(HashUtils.getSimHash(TxtUtils.readFile(args[0])),HashUtils.getSimHash(TxtUtils.readFile(args[i])));
            TxtUtils.writeFile(answer, answerPath);
        }
    }

    @Test
    public void mainTeatSame() {
        String str = "D:/test/orig.txt";
        String answerPath = "D:/test/answerSame.txt";
        double answer = HammingUtils.calculateSimilarity(HashUtils.getSimHash(TxtUtils.readFile(str)),HashUtils.getSimHash(TxtUtils.readFile(str)));
        TxtUtils.writeFile(answer,answerPath);
    }
}

測試結果:

測試結果

代碼覆蓋率:

代碼覆蓋率

結果文件:
總文件
文件1
文件2
 

五、異常處理

  1. 文本長度太短時,HanLp無法取得關鍵字,需要拋出異常。
 // 文本長度太短  HanLp無法取關鍵字
        try{
            if(str.length() < 200) throw new ExceptionUtils("文本過短!");
        }catch (ExceptionUtils e){
            e.printStackTrace();
            return null;
        }
public class ExceptionUtils extends RuntimeException {
        // 構造函數:僅帶消息參數
        public ExceptionUtils(String message) {
            super(message);
        }
}

測試:

public class ExceptionUtilsTest {
    @Test
    public void exceptionTest(){
        //str.length()<200
        System.out.println(HashUtils.getSimHash("世界這麼大"));
    }
    @Test
    public void exceptionTest0(){
        //長文本
        String str = TxtUtils.readFile("D:/test/orig.txt");
        System.out.println(HashUtils.getSimHash(str));
    }
}

結果

 

  1. 判斷命令行輸入參數的數量
if (args.length != 3) {
            System.out.println("請提供正確的參數:[原文文件] [抄襲版論文的文件] [答案文件]");
            return;
        }

 

六、附錄

PSP表格
PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 60 60
· Estimate · 估計這個任務需要多少時間 60 60
Development 開發 1130 1350
· Analysis · 需求分析 (包括學習新技術) 300 400
· Design Spec · 生成設計文檔 30 40
· Design Review · 設計覆審 30 40
· Coding Standard · 代碼規範 (為目前的開發制定合適的規範) 40 30
· Design · 具體設計 90 100
· Coding · 具體編碼 360 390
· Code Review · 代碼覆審 40 50
· Test · 測試(自我測試,修改代碼,提交修改) 240 300
Reporting 報告 130 110
· Test Repor · 測試報告 60 60
· Size Measurement · 計算工作量 40 30
· Postmortem & Process Improvement Plan · 事後總結, 並提出過程改進計劃 30 20
· 合計 1320 1520

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java程式的運行包含編寫、編譯和運行三個主要步驟。 1.在編寫階段: 開發人員在Java開發環境中輸入程式代碼,形成尾碼名為.java的Java源文件。 2.在編譯階段: 使用Java編譯器對源文件進行錯誤排查,並生成尾碼名為.class的位元組碼文件。 3.最後,在運行階段: JRE中的Java解 ...
  • 關於阿裡的通義靈碼,之前DD就給大家推薦過,雖然比起GitHub Copilot還有一些差距。但日常使用,大部分場景還是游刃有餘的。另外,它還是免費使用的,還要什麼自行車? 最近正好看到它們在搞活動,不管你之前是否已經使用,還是沒有體驗過,這次都推薦來嘗試一下!因為不管你覺得好不好,都有 拿啊 ...
  • Pandas無疑是我們數據分析時一個不可或缺的工具,它以其強大的數據處理能力、靈活的數據結構以及易於上手的API贏得了廣大數據分析師和機器學習工程師的喜愛。 然而,隨著數據量的不斷增長,如何高效、合理地管理記憶體,確保Pandas DataFrame在運行時不會因記憶體不足而崩潰,成為我們每一個人必須面 ...
  • 在前幾篇線程系列文章中,我們介紹了線程池的相關技術,任務執行類只需要實Runnable介面,然後交給線程池,就可以輕鬆的實現非同步執行多個任務的目標,提升程式的執行效率,比如如下非同步執行任務下載。 ...
  • 拓展閱讀 第一節 從零開始手寫 mybatis(一)MVP 版本。 第二節 從零開始手寫 mybatis(二)mybatis interceptor 插件機制詳解 第三節 從零開始手寫 mybatis(三)jdbc pool 從零實現資料庫連接池 第四節 從零開始手寫 mybatis(四)- myb ...
  • 故事 春天,辦公室外的世界總是讓人神往的,小貓帶著耳機,托著腮幫,望著外面美好的春光神游著... 一聲不和諧的座機電話聲打破這份本該屬於小貓的寧靜,“hi,小貓,線上有個客戶想購買A產品規格的商品,投訴說下單總是失敗,幫忙看一下啥原因。”客服部小姐姐甜美的聲音從電話那頭傳來。“哦哦,好,我看一下,把 ...
  • roncoo-education —— 一個分散式線上教育系統。目前主要功能有課程點播功能,支持多家視頻雲的接入,課程附件管理功能,支持多家存儲雲的接入,可以幫助個人或者企業快速搭建一個輕量級的線上教育平臺。 ...
  • 在Java多線程編程中,正確且安全地停止線程是一項關鍵技能。簡單粗暴地“殺死”線程不僅可能導致數據不一致性,還可能引發各種難以預測的錯誤。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...