|
Regex是一種模式比對形式,它通常用程式中。比如我們經常使用的grep工具,還是perl語言都使用了Regex。傳統的C++處理Regex是非常麻煩的,這也成為很多其他語言愛好者的笑柄,現在情況不一樣了,因為有了boost。 Boost是一個基於Template的開發原始碼庫,在這個庫中有很多子庫用來高效處理各方面的問題,比如字串拆分,格式化,線程等等,Boost對於每一個C++愛好者都是應該瞭解的,對於C++ Builder使用者如果能在熟練使用VCL的情況下再熟練使用Boost,我想一定如虎添翼。 一般來說,使用Boost是非常簡單,和使用其他STL庫沒有太大區別,但使用Boost的Regex庫則不那麼容易,因為這個庫還需要我們單獨編譯,下面我將詳細介紹如何使用。 如果你還不知道或者還沒有Boost的話,你可以去www.boost.org下載最新版本,作者使用的是1.30版本。將下載下來的zip包[1]解壓到任何你喜歡的目錄,比如D:\boost。 編譯Regex庫 前面已經提到,這個庫需要我們單獨編譯才能使用,為什麼不編譯好一起發布呢?主要是考慮到不同的編譯器需要不同的連結庫檔案和連結庫太大了。在命令列下,進入[%Boost]\Libs\RegEx\Build目錄,直接敲入make –fbcb6.bat命令開始編譯,這裡請大家注意了,如果你的電腦上同時安裝了BCB5,請一定要把path設定成為BCB6的bcc32.exe程式所在的目錄,否則可能使用BCB5的make程式,這樣雖然能編譯但最後不能使用。 編譯過程相當耗時,你需要耐心等待,最終編譯完成,會在[%Boost]\Libs\RegEx\Build目錄產生一個BCB6目錄,在這個目錄產生了很多lib檔案和dll檔案,把所有dll檔案複製到windows系統目錄,所以lib檔案複製到bcb6\lib目錄。如果你不想這麼麻煩的複製檔案,可以在編譯時間加入install參數,就像這樣make –fBcb6.bat install,不過作者還是比較喜歡前一種方式,這樣我可以知道到底產生了什麼檔案。現在編譯已經完成了,你可以體現boost的神奇魅力了。 一個測試程式 在BCB6中建立console程式,編寫下列代碼: #include #include #include #include int main() { using namespace boost; using namespace std; regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase); string s=""; deque result; regex_split(std::back_inserter(result),s,expression); copy(result.begin(),result.end(),ostream_iterator(cout,"\n")); int c; cin>>c; return 0; } 設定BCB6 Project屬性的Lib Path和Include Path為你安裝boost的目錄,運行你會看到結果: index.html 可以看到index.html已經從字串中提出出來了,那麼為什麼會是這樣呢? 代碼的核心部分是: regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase); 它用來設定如何匹配字串,上面亂七八糟的字串很難看懂,如果不瞭解Regex的書寫規則,上面代碼可以和天書媲美。 regbase::normal|regbase::icase 是解析參數設定,具體可以參考boost協助文檔。 Regex的書寫規則 具體的書寫規則,大家可以參看boost的文檔,我這裡做一下簡要說明: . (dot) 用來匹配任何一個字元,但不包括新行上的字元 * 閉包,任意有限次的自重複串連 + 有限次自重複串連,但至少出現一次 {} 指定可能的重複次數 例如: ba* 匹配 b ba baa baaa等 ba+ 匹配 ba baa baaaaaaaaa等 ba{1,5} 匹配 ba baa baaa baaaa baaaaa \ 逸出字元,有很多用途,根據參數設定而變化,最常見的就是類似於c語言\的用法 \s 匹配空格 \w 匹配一個單詞 \d 匹配數字 () 有兩種用法: 1是合并的作用,例如(ab)*匹配ab abab ababab等 2是確定匹配,也就是說在()中的字元將被最終拆解出來 根據上面這張表,我們可以很容易知道前面的那段天書如何解釋。 一個實際的例子 前一段時間在CSDN上有一篇文章,問題是有一種檔案結構如(類似): @People{ Age=19 Speek=”Hay,{name},how are you” } 問如何拆分字串得到@後面的名字,=兩邊的屬性名稱和屬性值,引號裡{}種的名字。 解決這個問題用Regex再合適不過了。 根據分析,我們可以這樣構造匹配規則: "@(.*?)\s*\\{" 匹配@開始的字元創,後面兩種類型如何構造匹配規則留給大家思考吧。 這樣我們可以輕易拆解這個例子。 效能分析 通過上面的討論,大家已經瞭解到boost的強大威力,那個效能又如何呢?為此我們再實際來拆分一個複雜的html代碼,看看到底需要花費多少時間。 為了節省篇幅,這裡就不列出html代碼了,不過可以告訴大家,這是一個又Word產生的大小為186K的html檔案,這個檔案中用到了很多
#include #include #include #include #include int main() { using namespace boost; using namespace std; TStringList* html=new TStringList(); html->LoadFromFile("D:\\1.htm"); regex expression("\\s+width=([^\"]*)\s+",regbase::normal|regbase::icase); DWORD start=GetTickCount(); for(int n=0;nCount;n++) { string s=html->Strings[n].c_str(); deque result; regex_split(std::back_inserter(result),s,expression); copy(result.begin(),result.end(),ostream_iterator(cout,"\n")); result.clear(); } start=GetTickCount()-start; delete html; cout int c; cin>>c; return 0; } 輸出結果為671毫秒,拆分得到1072個width屬性值,我們可以看到boost的效率是非常高的,雖然與一些角本語言比起來解析速度還是慢,但已經可以滿足大多數編程要求了。另外作者的電腦配置並不是非常高,相信拿到現在任何一台主流配置的電腦上都會優於作者的結果。 結束語 其實上面的強大威力只是boost的冰山一角,如果你不自己去體會,你很難想象到boost的強大威力。在boost裡還有很多使用的庫,比如格式化輸出,字串拆解,類型轉換等,這些庫使用起來也比較方便,大家可以自行參考boost文檔。在這些庫中還有兩個庫需要自行編譯,他們是Python和thread庫,而且這些庫的編譯需要專門的工具Jam,所以我們在編譯這些庫的時候還要編譯jam工具,而編譯jam工具也不是一件快樂的事情,麻煩同樣出現在如果你安裝了多個編譯器,如果讀者有興趣可以自己試一下。 不過BCB6並不支援全部boost庫,從boost提供的編譯器支援表可以看到[2],BCB6還是有相當多的庫不支援的,支援最好的是gcc/g++的編譯器,但也不是全部支援。希望borland下一個將要發布的C++編譯器可以支援更多C++標準。 -------------------------------------------------------------------------------- [1] 其實還有其他類型的包,但在windows系統下,你最好下載zip包 [2] Boost提供的編譯器支援表是針對BCB5的,對於BCB6的支援作者並沒有詳細測試,如果讀者有興趣可以自己測試boost附帶的測試代碼。
posted on 2005-10-08 11:24 痛並快樂著 閱讀(...) 評論(...) 編輯 收藏 重新整理評論重新整理頁面返回頂部 部落格園首頁博問新聞快閃記憶體程式員招聘知識庫導航
公告
Powered by:
部落格園
Copyright 痛並快樂著 |