【tips】【詞頻統計】中可能用到的資源,以C++為例


  前言

  我不知道C#什么情況,不過C++里面,什么參數都不傳時,argc=1,argv里面是當前程序名。當你傳入dir時,argc=2,當你傳入-e dir時,argc=3。

  這個文章十分適合有一點C語言基礎,然后想自己獨立完成這個作業的童鞋。預計只有一點點C語言基礎的童鞋只需要5個小時左右就能搞定~

  如果有幫助請點贊。。還有哦。。blog里肯定不能給出代碼的是吧,blog里面不能!!!~

  分析詞頻統計這個題目,主要需要實現3個部分:

  1. 遞歸的查找一個文件夾下面符合規則的文件。
  2. 對於每一個合法文件,進行讀入,按照“單詞規則”進行詞的划分。
  3. 對於所有的詞進行統計,排序,輸出。

  這肯定不會給出源碼。但是肯定對C語言基礎的童鞋獨立完成作業有很大的幫助!

  文件讀入

  這里給出一個簡單的方法:

  如果我們知道每個合法文件的絕對路徑,就可以依次打開文件進行讀取(用C的fopen或者C++的ifstream)。關鍵是如何知道一個文件夾下面所有的文件。如果你會使用CMD,就會知道在windows環境下dir這個指令和列出文件目錄有關。通過查看dir的幫助文檔,發現用如下命令可以遞歸的列出一個文件夾下面所有文件:

dir [dictionary] /S /B > FileDir.tmp

  並且cmd支持正則表達式,所以可以用*.txt等直接獲得合法的文件。后面的大於號表示將輸出保存到當前目錄下面的FilrDir.txt文件中:

  於是我們就獲得了所有需要統計的文件的絕對路徑。這些信息保存在當前目錄下的一個tmp文件中(其實就是一個文本文件)。關鍵是怎么在C++里面執行這個指令。stdlib.h里面有一個函數叫system(char* userCmd),表示在cmd里面執行userCmd命令。其中userCmd是一個字符串。所以我們可以在程序里面用system()函數執行那句命令,然后得到tmp文件。統計的時候,只需要把地址依次讀出,然后打開那個地址指向的文件。統計詞頻就可以。好吧。。看來這里有很多問題。。。

  顯然在你直接使用這個命令的時候不會出現任何問題。

system(argv[argc-1]);

  但在程序里面測試實際地址的時候,竟然有人寫了如下語句,然后還一直埋怨說調試過不了:

char str[100]="D:\n.txt";
system(str);

  我不想用咆哮體,但。。。但忍不住啊!!!你輸出回車的時候用的是什么啊?不是printf("\n");嗎?難道就木有發現\是個轉意字符嗎?正確的寫法是D:\\Dir好不好啊!!!

  

  單詞划分 這個用不用C++特性無所謂,唯一需要的是細心,不要漏掉規則。

 

  詞頻統計

  如果說,讓你統計有n個100以內的數字,每個數字出現的次數。這個很簡單,你肯定會開一個長度101的數組arr,然后每當k出現一次,arr[k]++。但現在是統計單詞出現次數。C++里面你可以是用一個東西叫做map(在map頭文件中)。用map可以實現一個“數組” arr,這個數組的下表就是單詞,保存的內容就是單詞出現的次數。比如有一個單詞叫buaa,那么通過map定義的“數組”,你可以實現arr["buaa"]++;這個操作。這個“數組”叫做map容器,可以當數組一樣使用。定義一個map容器很簡單:map的用法建議參考C++ primer。

map<string,int> wordMap;

  還有一個問題是怎么樣保存應該輸出哪個單詞,在這里我是用了另一個map<string, string>保存的。就是所有的單詞全換成小寫,作為下標。對於某個單詞輸出的時候,輸出的值是該單詞在第二個map對應的單詞,以及第一個map里對應的次數。

  排序輸出

  在這里你可能需要先了解vector頭文件中的vector,utility頭文件中的pair,以及剛才提到的map。這兩個數據結構都在C++primer中有詳細介紹,分別在P78,P306,P309。如果你不了解這3個東西,下面一段話很可能看不懂。不過沒有關系,你都有整個map容器了,大不了自己寫一堆代碼,把map的值全遍歷到一個自己的數據結構里面,然后排個序輸出。下面的方法只是講用C++的庫函數省了寫過多代碼。

  C++里面自帶sort函數,在algorithm頭文件中。sort函數可以排序數組,vector,等等(我不知道能不能排序map,沒有試過,因為不用考慮效率問題,當時直接把所有map的內容移到vector里面了)。因為最后的答案是<key,value>鍵值對,而pair就是這種形式。所以直接用pair保存每一個<單詞,次數>鍵值對。然后放在vector中。

pair<string,int> tmp;
tmp.first=wordTrans[mapIt->first];
tmp.second=mapIt->second;

  接下來對於vector(這里vector變量名是sortArray)直接sort就好了。

sort(sortArray.begin(),sortArray.end(),Compare);

  sort函數包含3個參數,分別是排序起始的位置,排序結束的位置,以及比較函數函數名。這個比較函數是自己寫的。

bool Compare(pair<string, int> a,pair<string, int>b){...}

  函數需要返回bool型,以便告訴sort,在什么情況下,我認為a<b。

  通過這種方式,只需要幾行代碼就能完成最后一步。工作量要小不少。

  以上就是整個作業的大體。寫下來大約100行左右。如果有什么問題或者需要接一下C++ primer,可以留言或者找我們小組的成員。

Z.XML

編輯:肖俊鵬

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM