課程 | 軟件工程1916|W(福州大學) |
---|---|
做業要求 | 結對第二次—文獻摘要熱詞統計及進階需求 |
結隊博客 | 221600328 221600106 |
Github地址 | 基礎需求 |
做業目標 | 實現一個可以對文本文件中的單詞的詞頻進行統計的控制檯程序。 |
具體分工 | 221600328:主要代碼及工做 221600106:部分代碼,編寫文檔 |
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 60 | 50 |
Estimate | 估計這個任務須要多少時間 | 1700 | 2050 |
Development | 開發 | 300 | 350 |
Analysis | 需求分析 (包括學習新技術) | 180 | 220 |
Design Spec | 生成設計文檔 | 60 | 70 |
Design Review | 設計複審 | 60 | 80 |
Coding Standard | 代碼規範 (爲目前的開發制定合適的規範) | 30 | 20 |
Design | 具體設計 | 180 | 220 |
Coding | 具體編碼 | 770 | 850 |
Code Review | 代碼複審 | 120 | 100 |
Test | 測試(自我測試,修改代碼,提交修改) | 80 | 70 |
Reporting | 報告 | 160 | 180 |
Test Repor | 測試報告 | 30 | 35 |
Size Measurement | 計算工做量 | 30 | 25 |
Postmortem & Process Improvement Plan | 過後總結, 並提出過程改進計劃 | 120 | 55 |
合計 | 2180 | 2325 |
WordCount基本需求
實現一個命令行程序,不妨稱之爲wordCount。
第一步、實現基本功能
輸入文件名以命令行參數傳入。例如咱們在命令行窗口(cmd)中輸入:
//C語言類
wordCount.exe input.txt
//Java語言
java wordCount input.txt
則會統計input.txt中的如下幾個指標
1.統計文件的字符數:java
2.統計文件的單詞總數,單詞:至少以4個英文字母開頭,跟上字母數字符號,單詞以分隔符分割,不區分大小寫。c++
3.統計文件的有效行數:任何包含非空白字符的行,都須要統計。git
4.統計文件中各單詞的出現次數,最終只輸出頻率最高的10個。頻率相同的單詞,優先輸出字典序靠前的單詞。github
5.按照字典序輸出到文件result.txt:例如,windows95,windows98和windows2000同時出現時,則先輸出windows2000正則表達式
6.輸出的格式爲
characters: number
words: number
lines: number
...
此次題目主要是兩個部分:字詞計數和文件讀寫,原本想用c++來進行編碼,後來發現使用Java更爲簡便,有許多類庫函數能夠直接調用來解決問題,因而就使用了Java。
思路主要是寫一個Count類,類裏包含各個小問題解決的方法,如CountCharacter,CountLine和CountWord。
使用BufferedReader讀文件,讀出來的數據用String存儲,對該字符串進行修改,獲取單詞及行數,最後重寫compare對單詞進行排序。
有了總體思路後,對每一個方法逐個擊破,便迎刃而解了。windows
一開始寫這個代碼十分不規範。。用的變量名簡直爲所欲爲,後面按照Java規範修改了一下,總體還行。app
類圖
(https://img2018.cnblogs.com/blog/1593605/201903/1593605-20190315170442501-135307741.png)ide
流程圖
函數
傳入文件名,統計非空行數,統計字符數,統計單詞數,統計最多的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進行切分能提升性能。
明輝是個很聰明勤奮的人,對此次做業作出了很大的貢獻我也協助他完成了基礎的工做。