課程連接:軟件工程1916|W(福州大學)
做業要求:結對第二次—文獻摘要熱詞統計及進階需求
結對學號:221600205 | 221600207
做業目標1:1、基本需求:實現一個可以對文本文件中的單詞的詞頻進行統計的控制檯程序。
做業目標2:2、進階需求:在基本需求實現的基礎上,編碼實現頂會熱詞統計器html
黃權煥:
1.主要代碼實現
2.需求分析討論
3.博客撰寫
4.代碼測試git
陳紅寶:
1.爬蟲代碼實現
2.需求分析討論
3.博客撰寫
4.代碼測試github
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) |
---|---|---|
Planning | 計劃 | |
• Estimate | • 估計這個任務須要多少時間 | 900 |
Development | 開發 | |
• Analysis | • 需求分析 (包括學習新技術) | 120 |
• Design Spec | • 生成設計文檔 | 60 |
• Design Review | • 設計複審 | 30 |
• Coding Standard | • 代碼規範 (爲目前的開發制定合適的規範) | 30 |
• Design | • 具體設計 | 120 |
• Coding | • 具體編碼 | 600 |
• Code Review | • 代碼複審 | |
• Test | • 測試(自我測試,修改代碼,提交修改) | 30 |
Reporting | 報告 | 60 |
• Test Repor | • 測試報告 | 30 |
• Size Measurement | • 計算工做量 | 30 |
• Postmortem & Process Improvement Plan | • 過後總結, 並提出過程改進計劃 | 30 |
合計 | 1110 | 2210 |
記得開始工做的時候是上週六(3月9號)。週五晚上發佈做業,大概看了一下需求。從感受上來看,有些多,也有些複雜。
因而,週六早上和下午完成其餘工做後,就開始討論本次做業了。
可是,問題發生了!個人Eclipse用不了,要從新配置環境變量。跟着百度上的教程,一步一步的走,但老是解決一個錯誤又出現另一個錯誤。期間,環境變量的配置方式都用了三種。花費一個晚上的時間,最後全部東西都卸載重裝,問題終於解決了!頓時鬆了一口氣。
但問題是,個人同伴,在這個晚上,已經把基礎需求代碼所有寫出來了。
就像那句話怎麼說:時間是講公平的,當你忙於一件事情的時候,有人已經把另一件事情忙完了!
有些慚愧,由於沒有太多的討論,以及對他有任何幫助!他一我的默默的完成了!
以後的一天也就是上週日(3月10號)晚上。我作的事情是理解同伴編寫的代碼。同時也理解做業的需求。
有不少收穫,也發現了一些問題,以後會一一道來。正則表達式
1.從文件中讀取字符流到緩衝區,判斷緩衝區的每一行字符,切割字符串(去掉非字母非數字的符號),將切割出來的字符串保存到字符數組中,並記錄有效行
2.將字符數組中的字符串轉換爲小寫格式(方便以後判斷和輸出)。循環判斷字數組符中的字符串前4個字符是不是小寫字母。若是是,則保存到哈希表中(方便字典序排序),並增長單詞數。若是不是,則捨去該字符串。
3.有哈希表中存儲的字符串,能夠方便的輸出單詞和詞頻。
4.算法思路:
獲取行數
將文件打開後,用readLine()函數逐行讀取文本內容並保存在fContent上,此時疊加行數。算法
獲取字符數
將字符串fContent讀取成功後,字符數+=fContent.length;windows
獲取單詞數
將fContent使用split(「\W+」)分割成只有可寫字符的單詞組存入String [] ch中,單詞數+=ch.length;數組
數據結構
使用HashMap保存單詞和使用頻率,不使用TreeMap的緣由是,TreeMap沒有自帶按值排序後,相同值按字典序排序的特性。而HashMap可使存儲、查找的時間效率都在O(1)內完成,而不是TreeMap的log(N);
值得注意的是,Map自己排序須要轉化成List,排序成功後因將結果應從新轉化爲LinkedHashMap。LinkedHashMap能夠按插入順序保存。數據結構
進階需求app
自定義輸入輸出
在類中額外保存輸入輸出名便可。函數
自定義詞頻統計輸出
在類中額外保存一個最大單詞數用來控制LinkedHashMap長度便可。
權重分析
在HashMap插值時,額外判斷是否來自Title,是的話記錄數+10,不然+1便可。
多參數的混合使用
讀取一行,依舊用split(「-「)函數分割成不一樣指令,分別調用函數便可。
public void getWord() { LinkedHashMap<String,Integer> list = sortMap(maxWordNum); try { FileOutputStream fos = new FileOutputStream(fileOutput); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter buff = new BufferedWriter(osw); String content = "characters: " + fByteCount + "\r\n"; content += "words: "+ getFWordCount() + "\r\n"; content += "lines: "+ fRowCount + "\r\n"; Iterator<String> iterator = list.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); content += "<" + key.replace("=", ">: ") + "\r\n"; //System.out.println(key.replace("=", ">: ")); } //System.out.print(content); buff.write(content); buff.flush(); fos.close(); } catch (FileNotFoundException e) { // TODO e.printStackTrace(); } catch (IOException e) { // TODO e.printStackTrace(); } }
public void setWord() { try { String fContent = ""; FileInputStream fis = new FileInputStream(fileInput); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); fWordCount = fByteCount = fRowCount = 0; while ((fContent = br.readLine()) != null) { if(fContent.length() > 3)// { fRowCount ++; if(fContent.charAt(0) == 'T') { fContent = fContent.substring(6, fContent.length()-1 ); fByteCount += fContent.length();// setMap(fContent,true); } else if(fContent.charAt(0) == 'A') { fContent = fContent.substring(9, fContent.length()-1 );//remove(Abstract: ) fByteCount += fContent.length();// setMap(fContent,false); } } } fis.close(); } catch (FileNotFoundException e) { System.out.print(""); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
public void setMap(String fContent,boolean isTitle) { String [] ch = fContent.split("\\W+"); for(int i = 0; i< ch.length ;i++) { if(ch[i].length()>=4) { ch[i] = ch[i].toLowerCase(); if (isLower(ch[i].charAt(0)) && isLower(ch[i].charAt(1)) && isLower(ch[i].charAt(2)) && isLower(ch[i].charAt(3)) ) { //System.out.print(ch[i]); fWordCount ++; if( map.containsKey(ch[i]) ) map.put(ch[i],(wValue & isTitle) ? map.get(ch[i])+10 : map.get(ch[i])+1); else map.put(ch[i], (wValue & isTitle) ? 10 : 1); } } } }
public LinkedHashMap<String,Integer> sortMap(int num) { List<Map.Entry<String,Integer>> list = new ArrayList<Map.Entry<String,Integer>>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o2.getValue() != o1.getValue() ? (o2.getValue() - o1.getValue()) : (o1.getKey()).toString().compareTo(o2.getKey()); //return (o1.getKey()).toString().compareTo(o2.getKey()); } }); LinkedHashMap<String,Integer> tmp = new LinkedHashMap<String,Integer>(); for (int i = 0; i < list.size() && i< num; i++) { String id = list.get(i).toString(); Integer value = list.get(i).getValue(); tmp.put(id, value); //System.out.println(id + (value)); } return tmp; }
public lib() { fileInput = "cvpr/result.txt"; } public lib(String fName) { fileInput = fName; setWord(); } public void setFileInput(String fName) { fileInput = fName; } public void setFileOutput(String fName) { fileOutput = fName; } public void setWValue(int num) { wValue = num > 0 ? true : false; } public void setMaxWordNum(int num) { if(num >= 0) maxWordNum = num; } public int getFWordCount() { return fWordCount; } public int getFRowCount() { return fRowCount; } public int getfByteCount() { return fByteCount; } public int getMaxWordNum() { return maxWordNum; } public int getMaxWordNum(int num) { return maxWordNum = num; } public boolean isLower(char c) { return (c>='a' && c<='z'); } public boolean isDigit(char c) { return c<='0' && c<='9'; }
爬蟲實現是我本身一步一步的,從沒據說過,到查資料,寫代碼,最後是輸出 result.txt文件,用了三個晚上加一個通宵,和其餘一些零零散散的時間。
怎麼說呢!仍是先描述一下學習的過程吧!由於用得時間多,學得也多嘛!
週一(3月11日)晚上,開始學習爬蟲之旅。有些惶恐,也有些期待。當時以爲這個爬蟲技術學會了,之後會有大用處。就像一個朋友開玩笑說:「學了爬蟲,之後均可以本身上起點小說網爬取小說內容了!」
我記得一開始百度搜索的時候,爬蟲軟件不少,我下載了一個叫「后羿」的爬蟲軟件,不過沒用上,由於要學習後本身編碼!
學習的過程,大可能是重複歷史。從網上找一些具體的代碼例子,看看別人怎麼寫代碼,又實現了哪些功能。
而我學習的過程,借鑑了五份代碼。都是一份一份的從網上查找,選取感受適合的。而後一邊敲寫,一邊理解。
第一份:關於URL連接輸出HTML所有信息。從這份中,我學到了URL連接以及獲取網頁html的內容。
第二份:從一段字符串中,使用正則表達式截取電話號碼。(當時還不知道正則表達式,只記得搜索相關資料的時候看見網上有人表示:「正則表達式寫錯了一點點,後面就所有錯了。」因而,謹慎細微,不敢擅自修改樣例中的正則表達式。但最後在本身理解正則表達式後發現,這好像也不是當時想的那麼難的。)
第三份:從單個網頁中截取須要的信息(用正則表達式)。當時在裏的時候,就是很謹慎的,正則表達式和對應網頁上的信息看了一遍又一遍,勉強理解了,但幾乎不會用。直到把正則表達式的規則看了許多遍,才豁然開朗。
第四份:是關於讀取從第一個頁面出發,而後讀取不少頁面的連接以及連接裏的內容。這份樣例代碼很少,但當時理解起來很繁瑣,頭都要炸了
第五份:和第三份同樣,是從單個網頁中截取須要的信息。我最後完成的代碼,大部分格式都是模仿這一份的。
完成篇:代碼爬取出論文後,依舊還有兩個改進,這個下面優化的時候會講。
private static String htmlFiter(String html,int num) { StringBuffer buffer = new StringBuffer(); String str1= ""; String str2= ""; // 匹配Title(題目),題目被包含在<div id="papertitle"> 和 </div>中 Pattern p1 = Pattern.compile("(<div id=\"papertitle\">)(.+?)(</div>*)"); Matcher m1 = p1.matcher(html); // 匹配Abstract(摘要),摘要被包含在<div id="abstract"> 和 </div>中 Pattern p2 = Pattern.compile("(\"abstract\")(.+?)(</div>*)"); Matcher m2 = p2.matcher(html); if(m1.find() && m2.find()) { str1 = m1.group(2); str1 = num+"\r\n"+"Title: "+str1+"\r\n"; // buffer.append("\nTitle: "); // buffer.append(str1); str2 = m2.group(2); str2 = str2.replace(">",""); str2 = "Abstract:"+str2+"\r\n"+"\r\n"; // buffer.append("\nAbstract: "); // buffer.append(str2); // buffer.append("\n"); try { File file = new File("D:\\result.txt"); FileWriter fw = new FileWriter(file,true); String str5 = str1; fw.write(str5); String str6 = str2 + System.getProperty("line.separator"); fw.write(str6); fw.close(); }catch(Exception e) { e.printStackTrace(); } } return buffer.toString(); }
private static String htmlFiter(String html,int num) { StringBuffer buffer = new StringBuffer(); pre_2 p2 = new pre_2(); String str = null; Pattern p = Pattern.compile("(<div id=\"content\">)(.*)(</div>*)"); Matcher m = p.matcher(html); if(m.find()) { str = m.group(2); String str1 = null; String str2 = null; Pattern p1 = Pattern.compile("(class=\"ptitle\">)(.+?)(a href=\")(content_cvpr_2018)(.+?)(_2018_paper.html\">)"); Matcher m1 = p1.matcher(str); while(m1.find()) { str1 = m1.group(5); str2 = ("http://openaccess.thecvf.com/content_cvpr_2018"+str1+"_2018_paper.html"); buffer.append(str2); buffer.append("\n"); p2.getTodayTemperatureInfo(str2,num); num++; } } return buffer.toString(); }
public class pre_main { pre_1 p1 = new pre_1(); String info = p1.getTodayTemperatureInfo("http://openaccess.thecvf.com/CVPR2018.py"); }
就像一道門,在你走進去以前,你會胡亂猜想甚至懼怕。由於你不知道門裏面是什麼,裏面對於你來講是黑漆漆的一片。而人生來就對未知的東西有着期待和恐懼。
待你真正走進這道門的時候,你感嘆一聲:「原來如此。」
當時我完成截取論文的爬蟲代碼的時候,用了三個晚上加一個通宵。但如今,你讓我再爬取難度類似的文檔時,我只要十分鐘。這大概就是師傅領進門的重要性吧!
(1)當時,我開始完成爬蟲代碼的時候,一共有兩個程序。第一個:爬取主頁中,關於論文連接的連接地址,保存到一個名叫 1.txt 文檔中。第二個:從 1.txt 文檔中,獲取連接地址,再從相應的地址獲取須要的論文標題和內容信息,保存到result.txt。
第一次完成的時候,截取的連接地址有兩個不符合要求,改了不少次正則表達式,甚至把對的改錯了!最後發現的問題是:有兩個連接的地址中後面的 「CVPR」是小寫,其餘的是大寫。發現這個的時候很開心,由於究竟了許久,最後在逐字對照正確爬取和錯誤爬取連接的時候發現。
(2)已經爬取了result.txt 後,還有一個問題是,會產生一個1.txt 文件。因而便須要優化,優化即是把上面兩個程序都封裝成包,最後在主程序中調用,既解決了產生多餘 1.txt 的要求,也知足了測試要求。
public void getWord() { LinkedHashMap<String,Integer> list = sortMap(maxWordNum); try { FileOutputStream fos = new FileOutputStream(fileOutput); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter buff = new BufferedWriter(osw); String content = "characters: " + fByteCount + "\r\n"; content += "words: "+ getFWordCount() + "\r\n"; content += "lines: "+ fRowCount + "\r\n"; Iterator<String> iterator = list.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); content += "<" + key.replace("=", ">: ") + "\r\n"; //System.out.println(key.replace("=", ">: ")); } //System.out.print(content); buff.write(content); buff.flush(); fos.close(); } catch (FileNotFoundException e) { // TODO e.printStackTrace(); } catch (IOException e) { // TODO e.printStackTrace(); } }
public void setWord() { try { String fContent = ""; FileInputStream fis = new FileInputStream(fileInput); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); fWordCount = fByteCount = fRowCount = 0; while ((fContent = br.readLine()) != null) { if(fContent.length() > 3)// { fRowCount ++; if(fContent.charAt(0) == 'T') { fContent = fContent.substring(6, fContent.length()-1 ); fByteCount += fContent.length();// setMap(fContent,true); } else if(fContent.charAt(0) == 'A') { fContent = fContent.substring(9, fContent.length()-1 );//remove(Abstract: ) fByteCount += fContent.length();// setMap(fContent,false); } } } fis.close(); } catch (FileNotFoundException e) { System.out.print(""); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
public void setMap(String fContent,boolean isTitle) { String [] ch = fContent.split("\\W+"); for(int i = 0; i< ch.length ;i++) { if(ch[i].length()>=4) { ch[i] = ch[i].toLowerCase(); if (isLower(ch[i].charAt(0)) && isLower(ch[i].charAt(1)) && isLower(ch[i].charAt(2)) && isLower(ch[i].charAt(3)) ) { //System.out.print(ch[i]); fWordCount ++; if( map.containsKey(ch[i]) ) map.put(ch[i],(wValue & isTitle) ? map.get(ch[i])+10 : map.get(ch[i])+1); else map.put(ch[i], (wValue & isTitle) ? 10 : 1); } } } }
public LinkedHashMap<String,Integer> sortMap(int num) { List<Map.Entry<String,Integer>> list = new ArrayList<Map.Entry<String,Integer>>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o2.getValue() != o1.getValue() ? (o2.getValue() - o1.getValue()) : (o1.getKey()).toString().compareTo(o2.getKey()); //return (o1.getKey()).toString().compareTo(o2.getKey()); } }); LinkedHashMap<String,Integer> tmp = new LinkedHashMap<String,Integer>(); for (int i = 0; i < list.size() && i< num; i++) { String id = list.get(i).toString(); Integer value = list.get(i).getValue(); tmp.put(id, value); //System.out.println(id + (value)); } return tmp; }
隊友在代碼實現和優化方面,很值得我學習。就好比說,在基礎需求的字典排序中,我還在思考是否是用字符數組保存字符串後,比較相同字符串,而後進行字典排序。這樣的方法,想一想就很麻煩!而隊友已經想到用哈希表保存數據,不管是字典安排序和輸出,都很方便。
其次,此次做業在兩人的溝通上遠不如上一次,做業類型不一樣是一個緣由。還有緣由是,我得增強代碼能力,但願能作到和隊友基本同步。
在一番辛勤勞動以及一份充碩的收穫以後,感悟頗多!
當時在閱讀理解同伴的基礎需求代碼上就有一些想法,如今補上。
大學已經三年了!過去的時光零零散散,孤獨的,寂寞的,大笑的,啜泣的。不管之前如何,如今都須要將心境沉浸下來了!而現在,有一個優秀的同伴,我很幸運。就像一樣學過數據結構,同伴能靈活運用,而我仍是處於老舊的思想。我要學習這樣的思惟方法,這一次的做業,是一個好的開端,但願能繼續下去。
內心的感悟頗多,但到了嘴邊,好像一切都簡單了!
簡單便簡單罷!再說一說自學的感覺。當一座你恐懼的高山被你踩再腳下時,再看看四周,便有「會當凌絕頂,一覽衆山小」的豪情,心中無限舒暢。就算當初學習過程當中,陷入困境時,也曾無奈。掙扎着,想要抓住什麼看成救命稻草。會發現,能依靠的有朋友,有本身。
當匆忙時,會過得很充實。偶爾停下腳步,會發現,這一刻之前忽略了的閒暇,是那麼的美好舒服。
總結了收穫,也有一些問題發現。 第一個是關於交流討論和實踐編碼的 上一次做業中,交流討論的時間不少,也從討論中明確了工做的需求和目的。在實際工做的時候,能夠引用一個成語就是:成竹在胸。 但此次做業中,一但涉及編寫代碼,討論的時間就會減小不少。並且當同伴寫出代碼後,就不知道從哪裏插手,好像本身修改就會破壞了同伴代碼的完整性。 這裏須要助教老師給咱們解答一下疑惑。 第二個是關於github使用的 老實說,由於之前沒有接觸過,並且是全英文的。根據老師的做業要求,fork 了連接,新建文件夾以及Pull Request ,等等操做後,不知道是否正確。我當時是創建了一個文件,而後把完成的代碼複製粘貼上去,選擇了new Pull Request。但後面又通過同窗的講解,好像要下載一個github,而後克隆文件什麼的。操做起來依舊是不知方向。 而我想向老師提議一下,若是下次有什麼新的網站啊,仍是軟件什麼須要用到。能不能像不少百度指導同樣,給一些圖片加上紅色箭頭標記,這樣能讓咱們快速的熟悉運用這些網站。也許在熟練的使用者眼裏,這只是簡單的操做,但對於初學者來講,是莫大的幫助了!