班級:軟件工程1916|W(福州大學)
做業:結對第二次—文獻摘要熱詞統計及進階需求
結對學號:221600315 黎煥明 221600319 李彥文
GitHub基礎需求項目地址:基礎需求
GitHub進階需求項目地址:進階需求
做業目標: 實現一個可以對文本文件中的單詞的詞頻進行統計的控制檯程序。在基本需求實現的基礎上,編碼實現頂會熱詞統計器。
具體分工:兩我的一塊兒負責分析需求,而後主要分析需求和文檔編寫主要是221600319,221600315主要負責部分代碼的實現。git
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
• Estimate | • 估計這個任務須要多少時間 | 660 | 1010 |
Development | 開發 | ||
• Analysis | • 需求分析 (包括學習新技術) | 180 | 60 |
• Design Spec | • 生成設計文檔 | 60 | 180 |
• Design Review | • 設計複審 | 60 | 120 |
• Coding Standard | • 代碼規範 (爲目前的開發制定合適的規範) | 無 | 無 |
• Design | • 具體設計 | 120 | 180 |
• Coding | • 具體編碼 | 240 | 300 |
• Code Review | • 代碼複審 | 0 | 200 |
• Test | • 測試(自我測試,修改代碼,提交修改) | 60 | 90 |
Reporting | 報告 | ||
• Test Report | • 測試報告 | 無 | 無 |
• Size Measurement | • 計算工做量 | 無 | 無 |
• Postmortem & Process Improvement Plan | • 過後總結並提出過程改進計劃 | 60 | 60 |
合計 | 660 | 1010 |
1. 基本需求:拿到題目後,看到基本需求時感受並不難,由於以前寫過相似的程序。要求知足三個功能,第一個是字符統計,第二個是單詞統計,第三個是詞頻統計。基本想法是將這三個功能分別寫到三個函數中,而後經過主函數調用返回相應的結果而且打印輸出。 2. 進階需求:是在基本需求的基礎上添加了參數判斷要求,新增的功能是加入詞組統計、單詞或詞組加入權重來計算最終的頻數。參數判斷單獨封裝,程序執行開始前就要將全部參數所有處理,方便以後使用,因此將參數判斷結果利用類屬性記錄。首先是加入權重這個問題,咱們的想法是直接在詞頻統計函數中加入判斷功能,若是開啓權重功能,那麼屬於TITLE的詞出現一次詞頻加10,其餘狀況都同樣。詞組統計功能,將這個功能單獨分裝成一個函數,利用正則來匹配詞組。 3. 資料查找:通過初步分析以後,上網看了一些介紹單詞統計,詞組統計的博客。大體瞭解了一下他們的思路,基本有兩種,一種是循環讀取判斷,再一種就是正則表達式匹配。咱們更傾向於後一種,這種方法比較直觀,體現再代碼上就是比較簡潔。
一共用兩個類,一個類是主程序入口Main,另一個是文本處理類Lib。Main類調用Lib類的靜態函數countChars、countWords、countLines分別統計字符數單詞數和行數,而後直接輸出,總體結構較爲簡單。
在基本功能完成後,進行測試時發現,若是測試文件比較大,程序讀取文件很是緩慢。經過debug發現是由於在讀取文件時使用了節點流,當文件讀取採用處理流方式時文件讀取會快不少。 由於剛開始寫時需求分析時間不多就開始寫代碼,致使咱們直接用了比較「土」的方法來實現,在進階需求寫爬蟲纔想起來用正則表達式實現能夠簡單地很是多。同時由於List<StringBuilder>的deleteChar方法效率很是低,咱們直接從新分配了內存,這部分處理時間複雜度縮短了很是多。
基礎需求實現比較簡單,可是countWords有必定的難度,剛開始並無想到用正則,而是直接遍歷。該方法接收StringBuilder的List並返回一個哈希表,該方法遍歷List的每一行,而後遍歷該行,若是找到單詞就檢查哈希表是否存在,若是哈希表存在該單詞就取出哈希表裏面的值+1並put進哈希表,若是哈希表不存在該單詞,則將該單詞直接put進哈希表,key爲單詞,value爲1。最後對哈希表進行按值排序並返回哈希表。
/** * 統計單詞數 * @param stringList * @return */ public static Map<String,Integer> countWords(List<StringBuilder> stringList){ Map<String,Integer> hashTable=new LinkedHashMap<>(); /* 計數器 */ int count; /* 是否爲單詞的標誌*/ boolean flag; /* 統計單詞數,若是存在單詞就放進哈希表 */ for(StringBuilder line:stringList){ count=0; flag=true; for(int i=0;i<line.length();++i){ if(line.charAt(i)<='z'&&line.charAt(i)>='a'){ ++count; }else if(line.charAt(i)<='9'&&line.charAt(i)>='0'){ if(count<4){ flag=false; } ++count; }else if(count>3&&flag){ String key=line.substring(i-count,i); /* 將單詞存入哈希表 */ hashTable.merge(key, 1, (a, b) -> a + b); count=0; }else{ count=0; flag=true; } } } /* 對哈希表進行排序 */ List<Map.Entry<String, Integer>> keyList = new LinkedList<Map.Entry<String, Integer>>(hashTable.entrySet()); keyList.sort( new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return Integer.compare(o2.getValue().compareTo(o1.getValue()), 0); } }); hashTable.clear(); for(Map.Entry<String, Integer> entry:keyList){ hashTable.put(entry.getKey(),entry.getValue()); } return hashTable; }
一樣是兩個類,一個類是主程序入口Main,另一個是文本處理類Lib。Main類調用Lib類的靜態函數getParameter得到參數,而後根據參數調用readFile讀取文件,以及打開輸出文件流,調用Lib類靜態函數getContent得到result.txt中的內容,而後Main類調用Lib類的靜態函數countChars、countWords、countLines分別統計字符數單詞數和行數,而後直接輸出。
類圖
github
進階需求總體比較難,主要難在詞組詞頻統計,將獲取到的文本放在兩個List<StringBuilder>中,行的一行字符串並記錄爲volatileString,使用正則表達式「[^a-z0-9]」+對volatileString進行分割,獲得一個數組的單詞,而後對數組內全部單詞使用"^[a-z]{4}[a-z0-9]*" m個一組進行正則匹配,肯定該單詞是否爲單詞,若是爲詞組,經過使用正則表達式「單詞1[^a-z0-9]+單詞2[^a-z0-9]+單詞m」對volatileString進行匹配獲得包含分隔符的完整單詞str(①),而後將str同基礎需求同樣存入map,而後經過volatileString.indexof(單詞1)和單詞1.length獲得單詞1初始位置beginindex和結束位置endIndex,而後將line賦值爲截取0-beginIndex和endIndex到volatileString.length(),以上操做是爲了不①位置匹配到不相符的結果。
/** * 統計詞組詞頻 * @param stringList * @return */ static Map<String,Integer> countWords(int delete, int m, List<StringBuilder> stringList){ Map<String,Integer> hashTable=new LinkedHashMap<>(); // 建立 Pattern 對象 String patternString = "^[a-z]{4}[a-z0-9]*"; Pattern pattern = Pattern.compile(patternString); boolean flag; for(StringBuilder line:stringList){ String volatileString= ""; if(line.length()>delete) { volatileString = line.substring(delete); } String notAlphaandNumber="[^a-z0-9]+"; String [] strings=volatileString.split(notAlphaandNumber); for(int i=0;i<strings.length-m+1;i++){ //是否全爲單詞 flag=true; for(int j=i;j<i+m&&j<strings.length;++j){ Matcher matcher = pattern.matcher(strings[j]); if(!matcher.find()){ flag=false; break; } } //若是全爲單詞 if(flag){ StringBuilder regEx= new StringBuilder(); for(int k=0;k<m;++k){ regEx.append(strings[i + k]); if(k!=m-1)regEx.append(notAlphaandNumber); } Pattern compile = Pattern.compile(regEx.toString()); Matcher matcher=compile.matcher(volatileString); if(matcher.find()){ hashTable.merge(matcher.group(), 1, (a, b) -> a + b); } } int beginIndex=volatileString.indexOf(strings[i]); // int endIndex=volatileString.indexOf(strings[i+m-1])+strings[i+m-1].length(); int endIndex=volatileString.indexOf(strings[i])+strings[i].length(); // volatileString=volatileString.substring(0,beginIndex)+volatileString.substring(endIndex); volatileString=volatileString.substring(0,beginIndex)+volatileString.substring(endIndex); } } return hashTable; }
剛開始也是使用基本需求那樣一個個比對,可是由於寫爬蟲的時候忽然想起來還有正則表達式,因而直接使用正則表達式進行匹配,而後使用Pattern.compile能夠更加快速的進行正則匹配,同時由於String是Immutable的,因此進階需求和基礎需求同樣都是使用StringBuilder進行字符串處理。
爬蟲是本身使用Python實現的,直接用正則匹配全部div爲ptitle的節點並獲取連接,而後對連接的網頁內容進行正則匹配將結果輸出到文件中。 使用方法:Python main.py
# coding=utf-8 import re import requests respose=requests.get('http://openaccess.thecvf.com/CVPR2018.py') text=respose.text urls=re.findall(r'class="ptitle".*?href="(.*?)"',text,re.S) output=open("result.txt","w",encoding='utf-8') j=0 print(respose.encoding) for i in urls: url='http://openaccess.thecvf.com/'+i respose = requests.get(url) text = respose.text paper_title = re.findall('id="papertitle">\n(.*?)<',text, re.S) abstract = re.findall('id="abstract" >\n(.*?)<', text, re.S) output.write(str(j)+"\n") output.write("Title: ") output.write(paper_title[0]) output.write("\n") output.write("Abstract: ") output.write(abstract[0]) output.write('\n\n\n') j+=1
重頭開始需求分析,而後重構代碼。
經過分離不一樣的模塊和功能下降總體的耦合度。
下次記得及時和多溝通。
221600319在本次做業中有點被我瞎帶節奏的感受,他的軟件工程思惟比較好,可以積極認真的分析項目的需求,可是本次由於我我的的緣由致使咱們此次做業提交比較遲,但願我本身之後能夠不要這麼瞎帶節奏了吧!而後但願之後可以一塊兒使用軟件工程的方法高效、好好的完成做業!