這個作業屬於哪個課程 | 軟體工程2024-雙學位(廣東工業大學) |
---|---|
這個作業要求在哪裡 | 軟體工程第二次作業 |
這個作業的目標 | 1. 在Gitcode倉庫中新建一個學號為名的資料夾 2. 記錄PSP表格 3. 使用程式語言完成論文查重程式 4. 使用Code Quality Analysis分析程式碼 5. 使用Studio Profiling Tools來最佳化程式碼 6. 使用Gitcode來管理程式碼 7. 使用單元測試對專案進行測試,並使用外掛檢視測試分支覆蓋率等指標 |
其他參考文獻 | 無 |
我的GitCode連結 |
- 我的GitCode連結 |
- 論文查重
- PSP表格
- 論文查詢程式設計
- SequenceMatcher基本使用
- 獲取匹配度
- 找出匹配的塊
- 查詢差異
- Differ類
- SequenceMatcher基本使用
- 使用者輸入的異常處理
- 使用cprofile進行效能分析
- 單元測試
- 程式碼覆蓋率
論文查重
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 30 | 60 |
·Estimate | ·估計這個任務需要多少時間 | 300 | 440 |
Development | 開發 | 60 | 40 |
·Analysis | ·需求分析(包括學習新技術) | 20 | 20 |
·Design Spec | ·生成設計文件 | 20 | 30 |
·Design Review | ·設計複審 | 10 | 30 |
·Coding Standard | ·程式碼規範(為目前的開發制定合適的規範) | 10 | 10 |
·Design | ·具體設計 | 30 | 50 |
·Coding | ·具體編碼 | 40 | 60 |
·Code Review | ·程式碼複審 | 10 | 20 |
·Test | ·測試(自我測試,修改程式碼,提交修改) | 30 | 50 |
Reporting | 報告 | 30 | 30 |
·TestReport | ·測試報告 | 20 | 10 |
·Size Measurement | ·計算工作量 | 10 | 10 |
·Postmortem & Process Improvement Plan | ·事後總結,提出過程改進計劃 | 10 | 20 |
·合計 | 330 | 440 |
論文查詢程式設計
首先是程式語言的選擇。由於python在資料分析領域已經很成熟,並且資料分析的率也很高,所以綜合考慮後,python是最佳選擇。
經過查詢一些部落格,發現python的difflib庫非常適合論文查重,所以本部落格站在巨人的肩膀上再進行開發。
difflib中常用兩個類:SequenceMatcher 和 Differ,它們都可以用來比較兩個序列(如字串、列表、元組等)之間的差異,並生成相應的結果,十分方便。
difflib
庫中的 SequenceMatcher
類是 Python 的一個非常有用的工具,用於比較兩個序列之間的相似度,找出它們之間最長的連續匹配的子序列。它可以用於比較任何型別的序列(如字串、列表或元組),非常適合於文字比較和差異分析等場景。以下是 SequenceMatcher
的一些基本使用方法和介紹:
SequenceMatcher基本使用
首先,你需要從 difflib
模組匯入 SequenceMatcher
類:
from difflib import SequenceMatcher
然後,你可以建立一個 SequenceMatcher
物件,透過傳入兩個序列來初始化:
matcher = SequenceMatcher(None, "文字1", "文字2")
在建立 SequenceMatcher
物件時,第一個引數是一個可呼叫物件,用於指定如何判斷兩個元素相等。通常,如果你只是想簡單地比較序列中的元素,可以將其設定為 None
,這樣比較就會使用預設的相等判斷。
獲取匹配度
SequenceMatcher
提供了 ratio()
方法來計算兩個序列之間的相似度(返回值是一個在 0 到 1 之間的浮點數,1 表示完全匹配):
similarity = matcher.ratio()
print(similarity)
找出匹配的塊
你可以使用 get_matching_blocks()
方法來獲取序列之間匹配的塊。這個方法返回一個列表,列表中的每個元素都是一個具有三個元素的元組 (a, b, n)
,表示序列 a
中從索引 a
開始、序列 b
中從索引 b
開始、長度為 n
的子序列是匹配的。
matching_blocks = matcher.get_matching_blocks()
for block in matching_blocks:
print(block)
查詢差異
difflib.SequenceMatcher
還提供了 get_opcodes()
方法,返回一個操作碼列表,描述如何從第一個序列變換到第二個序列。這個方法非常有用於實現差異比較工具,可以顯示兩個序列之間的差異。
opcodes = matcher.get_opcodes()
for tag, i1, i2, j1, j2 in opcodes:
print(f"{tag}: a[{i1}:{i2}] b[{j1}:{j2}]")
這裡的 tag
表示操作型別(如 'replace'、'delete'、'insert' 或 'equal'),i1:i2
表示第一個序列中受影響的範圍,而 j1:j2
表示第二個序列中受影響的範圍。
透過使用 SequenceMatcher
,你可以非常靈活和高效地進行序列比較和差異分析。它是文字處理、資料清洗等場景中非常實用的工具。
Differ類
Differ類可以用來生成兩個序列之間的差異報告,由於本程式只需要查詢兩篇論文的相似度,並不需要具體的分析,所以此處不展開。
使用者輸入的異常處理
在本次開發中,出現錯誤的主要原因是使用者在輸入可執行程式時,出現引數不正確,論文的格式不正確,或者路徑不正確。這些異常都需要在程式中進行處理,以提高程式的完整性和可靠性。
異常處理要用到sys庫和os庫,主要程式碼如下:
import sys
import os
#檔案格式和檔案路徑的異常處理
def check_file(file_path, expected_extension):
# 檢查檔案格式
if not file_path.endswith(expected_extension):
print(f"錯誤:檔案 '{file_path}' 不是期望的檔案格式 '{expected_extension}'。")
return False
# 檢查檔案是否存在
if not os.path.exists(file_path):
print(f"錯誤:檔案路徑不存在 '{file_path}'。")
return False
return True
# 獲取命令列引數
arguments = sys.argv
# 檢查引數數量是否正確
if len(arguments) != 4:
print("Usage: python main.py [原文檔案] [抄襲版論文的檔案] [答案檔案]")
sys.exit(1)
# 檢查檔案
if not(check_file(arguments[1], '.txt') and
check_file(arguments[2], '.txt') and
check_file(arguments[3], '.txt')):
sys.exit(2)
以下是對異常處理的結果:
使用cprofile進行效能分析
由上面兩圖的對比可以看出,在程式的執行中,異常處理的函式呼叫是佔最多的,尤其是對檔案路徑是否存在的處理,要大量呼叫'get' of 'str' objects方法,所以如果想讓程式執行得更快,可以將異常處理進行簡化,下圖是簡化後的結果(將檔案路徑是否存在部分的異常處理去掉):
我們可以看出,程式的函式呼叫次數打打減少了,而且執行時間也從0.397s下降到0.001s。所以最終還是要看功能和效能之間的取捨的。
單元測試
程式碼如下:(由於異常單元部分在上面已經測試完畢,所以只測試 calculate_similarity單元)
由上可知測試結果無異常
程式碼覆蓋率
由上可知,程式碼覆蓋率完整,沒有bug。