個人項目:論文查重

来源: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
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...