這個做業屬於哪一個課程 | 軟件工程1916|W(福州大學) |
---|---|
這個做業要求在哪裏 | 結對第二次—文獻摘要熱詞統計及進階需求 |
結對學號 | 221600117|221600122 |
這個做業的目標 | 實現一個可以對文本文件中的單詞的詞頻進行統計的控制檯程序。 |
Github倉庫地址 | 基礎部分github|進階部分github |
咱們兩個在此次做業中一塊兒實現了基礎部分的實現,每一個人寫了兩個功能,我主要負責基礎部分代碼的編寫和單元測試部分,還有git的使用方法的學習,基礎部分博客編寫。java
隊友主要負責進階部分的代碼編寫與相關部分的博客。c++
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
• Estimate | • 估計這個任務須要多少時間 | 480 | |
Development | 開發 | ||
• Analysis | • 需求分析 (包括學習新技術) | 120 | 150 |
• Design Spec | • 生成設計文檔 | 15 | 20 |
• Design Review | • 設計複審 | 10 | 5 |
• Coding Standard | • 代碼規範 (爲目前的開發制定合適的規範) | 5 | 1 |
• Design | • 具體設計 | 20 | 10 |
• Coding | • 具體編碼 | 180 | 240 |
• Code Review | • 代碼複審 | 30 | 10 |
• Test | • 測試(自我測試,修改代碼,提交修改) | 60 | 60 |
Reporting | 報告 | ||
• Test Report | • 測試報告 | 20 | 15 |
• Size Measurement | • 計算工做量 | 10 | 5 |
• Postmortem & Process Improvement Plan | • 過後總結, 並提出過程改進計劃 | 10 | 5 |
合計 | 480 | 521 |
首先拿到題目後,看完了整個題目後,感受基礎部分實現起來並非特別困難,咱們就準備次日開始着手解決基礎部分的代碼。我先學習了git的使用方法,經過百度找一些別人寫的博客瞭解了git的基本使用方法。這部分花了一上午的時間。git
在接下來就是對於代碼實現題目的思考。看到題目要求對字符進行處理統計,就決定使用C++來實現,由於C++對字符的操做更加簡單,也不須要特別複雜的操做。github
找資料的過程就是經過在網上搜索一些c++中對字符處理的函數方法,距離上次使用C++已經有一段時間了,此次正好複習了一下C++。算法
看到需求中有要求對代碼進行單元測試,還有進行性能分析。這些之前都沒有作過,因此學起來也花了一部分時間。網上對於這兩部分的講解資料並非特別多。框架
由於題目中有要求對接口的封裝:函數
你們的代碼都各有特點,若是如今咱們要把這個功能放到不一樣的環境中去(例如,命令行,Windows圖形界面程序,網頁程序,手機App),就會碰到困難:代碼散落在各個函數中,很難剝離出來做爲一個獨立的模塊運行以知足不一樣的需求。性能
幾個功能獨立出來,成爲一個獨立的模塊(class library, DLL, 或其它),這樣的話,命令行和GUI的程序都能使用同一份代碼。爲了方便起見,咱們稱之爲計算核心"Core模塊",這個模塊至少能夠在幾個地方使用:單元測試
- 命令行測試程序使用
- 在單元測試框架下使用
- 與數據可視化部分結合使用
因此就決定使用四個函數,分別來實現對文章字符數量的統計,對文章單詞數的統計和對文章行數的統計,以及前十高詞頻的單詞統計。學習
如圖,在需求一種,countChar,countLine,countWord,sortWord分別對應四個功能,在主程序Word Count中能夠直接調用。在設計函數的時候並無設計流程圖,由於他們都是獨立的單元,先實現了最簡單的功能,而後後面的函數構造都按第一個實現好的函數的形式寫就能夠。
單元測試的部分經過對各個函數進行了測試,每一個函數用了三組不一樣的輸入數據。一共設計了四個測試函數,對一下狀況進行了測試:
這是統計單詞數量的算法流程圖,題目中要求統計文件的單詞總數,單詞:至少以4個英文字母開頭,跟上字母數字符號,單詞以分隔符分割,不區分大小寫。因而就須要記錄單詞開頭的字母數量,來進行判斷。若是超過了四個以上的字母,說明該字符串爲單詞,若是讀到了分隔符,單詞數就加一。開頭字母數從頭開始計算,讀到數字若是已經不構成單詞,就把標誌位設爲-1。
這是對詞頻進行排序的流程圖。由於沒法直接對map直接進行排序,因此用到了vector中的pair,把map加入到vector中來進行排序再進行輸出。
統計單詞數的代碼
while((ch = fgetc(file)) != EOF) { if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { if (f >= 0)//單詞前四位是字母 f++; else//單詞前字母不足四位,後面字母不記錄 f = -1; } else if (ch >= '0' && ch <= '9' && f < 4)//開頭不足四位字母,不算單詞 { f = -1; } else//讀到分隔符 { if (f >= 4) cnt++; f = 0; } } //若最後一個單詞符合條件且到文件末尾 if (f >= 4) cnt++;
統計行數的代碼
while ((ch = fgetc(file)) != EOF) { //遇到換行符 if (ch == '\n') { //本行內容爲非空字符 if (f > 0) cnt++; f = 0; } //遇到非空字符 else if(ch != ' ' && ch != '\t') f++; } //最後一行不含回車符,特殊判斷 if (f > 0) cnt++;
統計字符數的代碼
while(fgetc(file) != EOF) { cnt++; }
排出前十詞頻的單詞代碼
while ((ch = fgetc(file)) != EOF) { if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { if (ch >= 'A' && ch <= 'Z') { ch += ('a' - 'A'); } if (f >= 0)//單詞前四位是字母 { f++; temp += ch; } else//單詞前字母不足四位,後面字母不記錄 f = -1; } else if (ch >= '0' && ch <= '9')//開頭不足四位字母,不算單詞 { if (f < 4) f = -1; else temp += ch; } else//讀到分隔符 { if (f >= 4) { cnt++; wmap[temp]++; } f = 0; temp = ""; } } if (f >= 4) { cnt++; wmap[temp]++; } MapSortOfValue(vec, wmap);
爬蟲:使用java
的jsoup
庫爬取HTML
文檔,而後生成DOM文檔。在DOM樹上,尋找到每一篇論文中的href連接發送請求,對於收到的文本中,解析出須要的Title和Abstract內容。
除了統計詞組相對於需求一有比較大的變化,其餘都是在需求一上作更多的判除操做,對於序號以及論文中的Title與Abstract要不加入計算,因此統計字符時也要加入單詞的判斷,這些與需求一大體相同,就很少加贅述。
統計詞組方面,主要難點是解決規定的詞組長度截取以及注意不能跨越兩個欄目,解決思路是:利用一個向量來模擬隊列。規定隊列長度爲詞組長度,新單詞進入加入隊尾,超過長度則拋出隊頭,當隊伍長度等於詞組長度時,隊列就是保留一個合法詞組。當遇到Title與Abstract時,隊列清空,就能夠作到不跨越兩個欄目。剩下排序就和需求一相同。核心部分流程圖以下:
核心代碼以下:
//...... while ((ch = fgetc(file)) != EOF) { if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { if (ch >= 'A' && ch <= 'Z') { ch += ('a' - 'A'); } if (f >= 0)//單詞前四位是字母 { f++; temp += ch; } else//單詞前字母不足四位,後面字母不記錄 f = -1; } else if (ch >= '0' && ch <= '9')//開頭不足四位字母,不算單詞 { if (f < 4) f = -1; else temp += ch; } else//讀到分隔符 { //當趕上title或者abstract時,模擬隊列清空 if (temp == "title" && temp == "abstract") que.clear(); if (f >= 4 && temp != "title" && temp != "abstract") { que.push_back(temp); //維持詞組的規定長度 if (que.size() > Len) que.erase(que.begin()); //符合長度,加入詞組map中 if (que.size() == Len) { tt = ""; k = 0; for (vt = que.begin(); vt != que.end(); vt++) { k++; tt += *vt; if (k < Len) tt += " "; } wmap[tt]++; } } f = 0; temp = ""; } } //......
在計算詞頻出現的時候,須要判斷是否爲單詞,這部分和在統計單詞數量的時候的代碼有部分重合了,也就是說須要重複的計算相同的部分,會花掉一部分時間,這部分代碼的設計存在着問題。
部分代碼以下
TEST_METHOD(TestMethod1)//測試字符數是否正確 { FILE *file; char* fn = "input1.txt"; fopen_s(&file, fn, "r"); int count = 102; Assert::AreEqual(countChar(fn), count); }
這是一段測試字符數是否正確的代碼,經過input1.txt的文件傳入數據,而後驗證字符數是否與預計數相等。
通過測試,10個測試點均經過測試。測試代碼的思路上面已經提到。
經過圖片能夠明顯看出,在統計詞頻或者詞組頻率(後面的提升部分)中所須要的運算量更大,因此更加耗費計算機資源。
關於單元測試和性能分析,是之前歷來沒有接觸過的,只能在網上查找資料來學習。可是相關的資料很是的很差找。因此資料就花掉了不少時間。還有git的使用,不過還好有Linux使用的基礎,學起來也還相對輕鬆。
剩下的困難就是在代碼方面的困難了。理解題目需求花了不少時間,常常寫着寫着發現好像不符合題目的要求,而後就又從新改。
解決辦法就是必定要先理解了需求,再開始着手。否則後期會很麻煩,前面努力都白費了。
隊友的寫代碼能力很強,進階功能基本都靠他來實現了。原本都要放棄了進階功能的部分,他說想試一下就作了。
不怕困難,值得學習!