作業描述
課程 | 軟體工程1916|W(福州大學) |
---|---|
作業要求 | 結對第二次—文獻摘要熱詞統計及進階需求 |
結隊部落格 | 221600328 221600106 |
Github位址 | 基礎需求 |
作業目标 | 實作一個能夠對文本檔案中的單詞的詞頻進行統計的控制台程式。 |
具體分工 | 221600328:主要代碼及工作 221600106:部分代碼,編寫文檔 |
簽入記錄

作業正文
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 60 | 50 |
Estimate | 估計這個任務需要多少時間 | 1700 | 2050 |
Development | 開發 | 300 | 350 |
Analysis | 需求分析 (包括學習新技術) | 180 | 220 |
Design Spec | 生成設計文檔 | 70 | |
Design Review | 設計複審 | 80 | |
Coding Standard | 代碼規範 (為目前的開發制定合适的規範) | 30 | 20 |
Design | 具體設計 | ||
Coding | 具體編碼 | 770 | 850 |
Code Review | 代碼複審 | 120 | 100 |
Test | 測試(自我測試,修改代碼,送出修改) | ||
Reporting | 報告 | 160 | |
Test Repor | 測試報告 | 35 | |
Size Measurement | 計算工作量 | 25 | |
Postmortem & Process Improvement Plan | 事後總結, 并提出過程改進計劃 | 55 | |
合計 | 2180 | 2325 |
需求分析
WordCount基本需求
實作一個指令行程式,不妨稱之為wordCount。
第一步、實作基本功能
輸入檔案名以指令行參數傳入。例如我們在指令行視窗(cmd)中輸入:
//C語言類
wordCount.exe input.txt
//Java語言
java wordCount input.txt
則會統計input.txt中的以下幾個名額
1.統計檔案的字元數:
- 隻需要統計Ascii碼,漢字不需考慮
- 空格,水準制表符,換行符,均算字元
2.統計檔案的單詞總數,單詞:至少以4個英文字母開頭,跟上字母數字元号,單詞以分隔符分割,不區分大小寫。
- 英文字母: A-Z,a-z
- 字母數字元号:A-Z, a-z,0-9
- 分割符:空格,非字母數字元号
- 例:file123是一個單詞,123file不是一個單詞。file,File和FILE是同一個單詞
3.統計檔案的有效行數:任何包含非空白字元的行,都需要統計。
4.統計檔案中各單詞的出現次數,最終隻輸出頻率最高的10個。頻率相同的單詞,優先輸出字典序靠前的單詞。
5.按照字典序輸出到檔案result.txt:例如,windows95,windows98和windows2000同時出現時,則先輸出windows2000
- 輸出的單詞統一為小寫格式
6.輸出的格式為
characters: number
words: number
lines: number
: number
...
解題思路
這次題目主要是兩個部分:字詞計數和檔案讀寫,本來想用c++來進行編碼,後來發現使用Java更為簡便,有許多類庫函數可以直接調用來解決問題,于是就使用了Java。
思路主要是寫一個Count類,類裡包含各個小問題解決的方法,如CountCharacter,CountLine和CountWord。
使用BufferedReader讀檔案,讀出來的資料用String存儲,對該字元串進行修改,擷取單詞及行數,最後重寫compare對單詞進行排序。
有了整體思路後,對每個方法逐個擊破,便迎刃而解了。
代碼規範
一開始寫這個代碼十分不規範。。用的變量名簡直随心所欲,後面按照Java規範修改了一下,整體還行。
設計說明
類圖
(https://img2018.cnblogs.com/blog/1593605/201903/1593605-20190315170442501-135307741.png)
流程圖
子產品設計
子產品說明
傳入檔案名,統計非空行數,統計字元數,統計單詞數,統計最多的10個單詞及其詞頻
方法說明
傳入檔案名
CountCharacter:計算字元數
CountWord:計算單詞
CountLine:計算行數
關鍵代碼
統計單詞及計算詞頻部分,使用split正規表達式分詞,存入HashMap,重寫compare,存入List進行排序。
public int CountWord() {
int wordNum=0;
String regex="[^A-Za-z0-9]";
String textLowerCase= text.toLowerCase();
String textcontents = textLowerCase.replaceAll(regex, " ");
String[] textarrays = textcontents.split("\\s+");
for(int i=0; i<textarrays.length;i++)
{
if(textarrays[i].length()>=4)
if(Character.isLetter(textarrays[i].charAt(0)) &&
Character.isLetter(textarrays[i].charAt(0)) &&
Character.isLetter(textarrays[i].charAt(0)) &&
Character.isLetter(textarrays[i].charAt(0)))
{
wordNum++;
if(!map.containsKey(textarrays[i]))
map.put(textarrays[i],1);
else
{
int num=map.get(textarrays[i]);
num++;
map.put(textarrays[i], num);
}
}
}
hotWords=Sort(map);
return wordNum;
}
public static List<HashMap.Entry<String, Integer>> Sort(Map m){
Map<String, Integer> map = new HashMap<String, Integer>();
// 通過ArrayList構造函數把map.entrySet()轉換成list
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(m.entrySet());
// 通過比較器實作比較排序
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String,Integer> mapping1, Map.Entry<String, Integer> mapping2) {
if(mapping1.getValue()==mapping2.getValue())
return mapping1.getKey().compareTo(mapping2.getKey());//字典排序
return mapping2.getValue()-mapping1.getValue();//從大到小
}
});
return list;
}
異常處理
對于各個異常情況都會列印異常資訊,如下
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
性能分析
如圖,大部分開銷來自于單詞技術部分。
單元測試
共設計了10組測試,分别有普通字元,換行符,空格,單詞大小寫,控制字元等。
以下是空白檔案的測試,分别有統計單詞,行數,字元的測試。
改進思路
如圖,在IO上有巨大的開銷,主要在計算行數時又通路了一遍檔案,導緻過度的IO,性能下降,應先将檔案資料暫存,後續對該檔案進行通路,減少IO,提高性能。
另外分割字元的函數split開銷也挺大,或許使用stringTokenizer進行切分能提高性能。
遇到的困難和解決方法:
- 需求的了解
- 解決方法:無可避免又在需求上産生疑問,果然對需求的清晰了解是首先,也是最重要的一步,通過與同學助教探讨解決問題。
- 使用性能分析,單元測試工具及git的使用
- 解決方法:首次使用這些工具,對工具的不熟悉,通過詢問同學及上網查找資料解決。
- 編碼能力不足
- 解決方法:個人編碼能力不足,以至于編寫代碼花了很多的時間,定痛改前非,提高程式設計能力
評價隊友
和隊友溝通良好,合作愉快!