做業連接 結對第二次—文獻摘要熱詞統計及進階需求html
-Github
-基礎需求(https://github.com/swc221500201/PairProject1-C/)
-進階需求(https://github.com/swc221500201/PairProject2-C/)java
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
Estimate | 估計這個任務須要多少時間 | 1420 | |
Development | 開發 | ||
Analysis | 需求分析 (包括學習新技術) | 60 | 50 |
Design Spec | 生成設計文檔 | 100 | 200 |
Design Review | 設計複審 | 60 | 80 |
Coding Standard | 代碼規範 (爲目前的開發制定合適的規範) | 120 | 180 |
Design | 具體設計 | 120 | 170 |
Coding | 具體編碼 | 660 | 720 |
Code Review | 代碼複審 | 60 | 120 |
Test | 測試(自我測試,修改代碼,提交修改) | 90 | 100 |
Reporting | 報告 | ||
Test Repor | 測試報告 | 60 | 90 |
Size Measurement | 計算工做量 | 60 | 70 |
Postmortem & Process Improvement Plan | 過後總結, 並提出過程改進計劃 | 30 | 60 |
合計 | 1420 | 1840 |
剛剛接觸題目以後第一反應就是用c++的文件流操做來挨個讀取和分隔單詞,而且很快的寫出了能夠運行的源碼,後續單詞統計排序功能,本身手動寫了一些程序,雖然實現了排序功能,不過在文本大小超過1M以上,速度就明顯更不上了,在CSDN和博客園上學習了幾篇相關的博客,發現用哈希表是個不錯的選擇,而C++的map容器又正好適合這個功能,內部的紅黑樹實現使得插入和排序速度快了很多,通過改進以後速度上有了很大提高。node
在考慮好實現基礎功能和進階需求以後:python
int countCharacter(string f);//f爲要統計的文件路徑 返回int類型的字符個數 int countLine(string f);//f爲要統計的文件路徑 返回int類型的行數 int countWords(string f);//f爲要統計的文件路徑 返回int類型的單詞個數 void sortwordCount(string f, string resultTxt);//排序文件f單詞並輸出到文件 resultTxt
void countWordsWithWeight(string f, string resultTxt, int w);//權重統計,f爲要統計的文件路徑 //w爲權重選擇 並輸出到文件 resultTxt void countGroupWordsWithLength(string f, string resultTxt, int n);//f爲要統計的文件路徑 並輸出到文件 resultTxt ,n爲用戶自定義詞組長度 .....
如下是使用命令行運行時的主要寫法,即把argv[i]挨個判斷並執行相關操做ios
for (int i = 0; i < argc; ++i) { if (string(argv[i]) == "-i"){ } else if(){ } ...... }
爬蟲javac++
爬蟲的爬取速度太慢,爬取所有900多條論文消息須要花費近一分鐘,若是可以啓用線程應該能大幅度提升速度,不過限制於時間沒有實現。git
基礎功能github
其實我以爲統計行數,統計單詞,統計字符的三個功能能夠集中於一個函數,這樣能夠在分析統計的時候節約兩遍的讀取時間。不過助教說了這是爲了使功能獨立。api
進階功能緩存
進階功能基於基礎功能,因此仍是以爲要改進的是基礎功能。
//f:要進行字符統計的文件路徑 //返回值 字符數 //c >= 0 && c <= 127 由於爬取的文件包含法語字符因此用c++的 isascii(c)判斷會報錯 int countCharacter(string f) { int ascii = 0; ifstream read; read.open(f, ios::in); char c; while (!read.eof()) { read >> c; if (c >= 0 && c <= 127) ascii++; } read.close(); return ascii; } //f:要進行統計的文件路徑 //返回值 行數 //eachline.empty()劃去空行 int countLine(string f) { ifstream input(f, ios::in); string eachline; int line = 0; while (getline(input, eachline)) { if (!eachline.empty()) line++; } input.close(); return line; } //f:要進行統計的文件路徑 //返回值 單詞數 //裏面的isword()爲自定義的單詞判斷函數 自動過濾不符合題意單詞 int countWords(string f) { int wordNum = 0; ifstream input; input.open(f, ios::in); string aline; string content; string::size_type start = 0; string::size_type end = aline.find_first_of(" ");//空格做爲單詞分隔符 while (getline(input, aline)) { //爲了不溢出,保存一個string對象size的最安全的方法就是使用標準庫類型string::size_type string::size_type start = 0; string::size_type end = aline.find_first_of(" ");//空格做爲單詞分隔符 while (end != string::npos) //npos就是這一行到頭啦; { string content = aline.substr(start, end - start); if (isword(content))//這個單詞從未出現 wordNum++; start = end + 1; end = aline.find_first_of(" ", start);//空格做爲單詞分隔符 } } input.close(); return wordNum; } //f:要進行統計的文件路徑 //返回值 無 //利用map容器來存儲統計單詞詞頻 multimap來實現單詞字典順序輸 void sortwordCount(string f) { ofstream out(resultTxt,ios::app); ifstream input; input.open(f, ios::in); string eachline; map<string, int> mapA; //第一個存單詞,第二個存單詞出現的次數; while (getline(input, eachline)) { //爲了不溢出,保存一個string對象size的最安全的方法就是使用標準庫類型string::size_type string::size_type start = 0; string::size_type end = eachline.find_first_of(" ");//空格做爲單詞分隔符 while (end != string::npos) //npos就是這一行到頭啦; { string content = eachline.substr(start, end - start); if (isword(content)) { tolowerString(content);//把content內容轉換爲小寫 便於輸出和統計 //if (!isLetter(content[end])&&!isdigit(content[end])) // content.erase(content.end()); map<string, int>::iterator it = mapA.find(content); if (it == mapA.end())//這個單詞從未出現 mapA.insert(pair<string, int>(content, 1));//賦值的時候只接受pair類型; else ++it->second;//單詞存在 } start = end + 1; end = eachline.find_first_of(" ", start);//空格做爲單詞分隔符 } } multimap<int, string, greater<int> > mapB;//按int排序的multimap //轉移mapA for (map<string, int>::iterator it1 = mapA.begin(); it1 != mapA.end(); ++it1) { mapB.insert(pair<int, string>(it1->second, it1->first)); } //界面輸出前十 int i = 0; for (map<int, string>::iterator it2 = mapB.begin(); i < 10&&it2!=mapB.end(); ++it2, ++i) cout <<"<"<<it2->second <<">:"<< it2->first << endl; //輸出排序好的map for (map<int, string>::iterator it2 = mapB.begin(); it2 != mapB.end(); ++it2) { // if ((it2->first) > 1) out << "<" << it2->second << ">:" << it2->first << endl; } out.close(); input.close(); }
//f:要進行統計的文件路徑 //返回值 無 //實現方法與基礎功能裏差很少,區別在於過濾了title: 和abstract: //爲了簡潔如下只顯示關鍵段代碼 void sortwordCount(string f) { if (isAbstract(eachline.substr(start, end - start)) || isTitle(eachline.substr(start, end - start))) { start = end + 1; end = eachline.find_first_of(" ", start);//空格做爲單詞分隔符 } } //f:要進行統計的文件路徑 w 是否開啓權重統計 0關閉 1開啓 //返回值 無 //實現方法與基礎功能裏差很少,區別在於增長了權重統計功能 void countWordsWithWeight(string f, int w) { flag = isTitle(eachline.substr(start, end - start)); ///不統計title和abstract if (isAbstract(eachline.substr(start, end - start))||isTitle(eachline.substr(start, end - start))) { start = end + 1; end = eachline.find_first_of(" ", start);//空格做爲單詞分隔符 } while (end != string::npos) //npos就是這一行到頭啦; { string content = eachline.substr(start, end - start); if (isword(content)) { tolowerString(content);//把content內容轉換爲小寫 便於輸出和統計 map<string, int>::iterator it = mapA.find(content); if (it == mapA.end())//這個單詞從未出現 mapA.insert(pair<string, int>(content, 1));//賦值的時候只接受pair類型 else { if (w == 0 || flag == false) ++it->second;//單詞存在 else if (w == 1 && flag == true) { it->second+=10;//單詞存在+= 10; } } } start = end + 1; end = eachline.find_first_of(" ", start);//空格做爲單詞分隔符 } } } //f:要進行統計的文件路徑 n 用戶自定義的詞組長度 //返回值 無 //實現方法:從流裏讀取到第n個分隔符後截斷 void countGroupWordsWithLength(string f,int n) { while (getline(input, eachline)) { //爲了不溢出,保存一個string對象size的最安全的方法就是使用標準庫類型string::size_type string::size_type start = 0; string::size_type end = eachline.find_first_of(" ");//空格做爲單詞分隔符 ///不統計title和abstract if (isAbstract(eachline.substr(start, end - start)) || isTitle(eachline.substr(start, end - start))) { start = end + 1; end = eachline.find_first_of(" ", start);//空格做爲單詞分隔符 } content = eachline.substr(start, end-start); for (i = 0; i < content.size() && cntNum < n; ++i) { if (content[i]==' ') cntNum++; } end = end + i; }
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class Spiter { // TODO Auto-generated method stub public static void main(String[] args) throws IOException { Document doc=Jsoup.connect("http://openaccess.thecvf.com/CVPR2018.py").maxBodySize(0).get(); Elements listClass = doc.getElementsByAttributeValue("class", "ptitle"); Document paper; int num=0; File file=new File("spider.txt"); Writer out=new FileWriter(file); try { System.out.print("爬取開始\n"); for(Element element:listClass) { String link = element.getElementsByTag("a").attr("href"); link="http://openaccess.thecvf.com/"+link; paper=Jsoup.connect(link).get(); Element Etitle=paper.getElementById("papertitle"); Element Eabstr=paper.getElementById("abstract"); String abstr=Eabstr.text(); String title=Etitle.text(); out.write(num+"\r\n"); out.write("Title: "+title+"\r\n"); out.write("Abstract: "+abstr+"\r\n"); // \r\n即爲換行 out.write("\r\n"); out.write("\r\n"); num++; out.flush(); // 把緩存區內容壓入文件 } System.out.print("爬取結束"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.close(); } }
File *input = fopen("input.txt","r"); File *ans = fopen("ans.txt","r"); String getAns,getInput; while(!getline(getInput,input)){ getline(getAns,input); if(!getAns.equal(getInput)) showMessage(); } cout<<"success"<<endl;
好久沒有接觸到文件的操做,對於c++的api比較生疏,從新熟悉的過程花了很多時間,另外在爬蟲上也花了很多時間。例如Jsoup.connect()函數會限定一個默認的1M大小,使得我爬取的數據只有500多條,然而其餘隊伍用python作出來的卻有900多條,正當準備重寫的時候,隊友發現了這個問題,爲咱們節省了很多時間。以及後期需求不斷變動,每次都要從新考慮。不過好在此次的配合默契了很多。
經過此次做業,咱們能夠說從新學習了一遍c++,對相關知識有了更深刻的理解和掌握。完成基礎需求後發現時間還比較充裕,便去嘗試寫了一下進階需求,在這個過程當中接觸了爬蟲,開始時遇到了一些問題,好在隊友間相互配合探討,成功發現並解決了問題,使咱們進一步體會到了合做的優點。