歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++ TR1正則庫使用示例

[背景介紹]
要想在程序中使用正則表達式,首先需要有庫支持.目前比較有影響的C++正則庫主要有GNU Regex Library,它是glibc的一部分.另一個就是PCRE全稱是Perl Compatible Regular Expressions.從名字我們可以看出PCRE庫是與Perl中正則表達式相兼容的一個正則表達式庫.PCRE是免費開源的庫,它是由C語言實現的,這裡是它的官方主頁:http://www.pcre.org/ PCRE++是一個對PCRE庫的C++封裝.轉帖一篇相關介紹的文章: http://www.linuxidc.com/Linux/2012-01/52297.htm 
當然了,我們知道TR1中也包含了一個正則庫,來自Boost的 regex.既然標准庫中有相應的功能,自然優先使用標准庫提供的功能(TR1還不是標准庫,不過也是遲早的事).
現在有不少編譯器已經完全實現了TR1庫,這裡要表揚一下微軟,其在C++編譯器上所做的努力和獲得的進步有目共睹.VC++ 2008就已經完全實現了TR1庫,VC++ 2010甚至已經迫不及待的把 tr1 名稱空間合並到 std 中,急迫之情可見一斑,可惜C++ 0x遙遙無期啊.當然還有一向,繼續牛著的 GNU C++編譯器也完全支持 tr1 庫. http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.tr1
應該說使用 tr1 庫的外部條件已經完全成熟了.

[代碼示例]
在VC++ 2010中建立一個 Win32 控制台工程,選中UNICODE支持.
[cpp]
  1. #include <iostream>   
  2. #include <string>   
  3. #include <regex>   
  4.   
  5. int _tmain(int argc, _TCHAR* argv[])  
  6. {  
  7.     std::locale loc("");  
  8.     std::wcout.imbue(loc);  
  9.   
  10.     std::wstring text(_T("我的IP地址是:109.168.0.1."));  
  11.     std::wstring newIP(_T("127.0.0.1"));  
  12.     std::wstring regString(_T("(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"));  
  13.   
  14.     // 表達式選項 - 忽略大小寫   
  15.     std::regex_constants::syntax_option_type fl = std::regex_constants::icase;  
  16.       
  17.     // 編譯一個正則表達式語句   
  18.     std::wregex regExpress(regString, fl);  
  19.   
  20.     // 保存查找的結果   
  21.     std::wsmatch ms;  
  22.   
  23.     // 判斷是否全行匹配   
  24.     if(std::regex_match(text, ms, regExpress))  
  25.     {  
  26.         std::wcout<<_T("正則表達式:")<<regString<<_T("匹配:")<<text<<_T("成功.")<<std::endl;  
  27.     }  
  28.     else  
  29.     {  
  30.         std::wcout<<_T("正則表達式:")<<regString<<_T("匹配:")<<text<<_T("失敗.")<<std::endl;  
  31.     }  
  32.   
  33.     // 查找   
  34.     if(std::regex_search(text, ms, regExpress))  
  35.     {  
  36.         std::wcout<<_T("正則表達式:")<<regString<<_T("查找:")<<text<<_T("成功.")<<std::endl;  
  37.         for(size_t i= 0; i < ms.size(); ++i)  
  38.         {  
  39.             std::wcout<<_T("第")<<i<<_T("個結果:\"")<<ms.str(i)<<_T("\" - ");  
  40.             std::wcout<<_T("起始位置:")<<ms.position(i)<<_T("長度")<<ms.length(i)<<std::endl;  
  41.         }  
  42.         std::wcout<<std::endl;  
  43.   
  44.         // 替換1   
  45.         text = text.replace(ms[0].first, ms[0].second, newIP);  
  46.         std::wcout<<_T("替換1後的文本:")<<text<<std::endl;  
  47.     }  
  48.     else  
  49.     {  
  50.         std::wcout<<_T("正則表達式:")<<regString<<_T("查找:")<<text<<_T("失敗.")<<std::endl;  
  51.     }  
  52.   
  53.     // 替換2   
  54.     newIP = _T("255.255.0.0");  
  55.     std::wstring newText = std::regex_replace( text, regExpress, newIP);  
  56.     std::wcout<<_T("替換2後的文本:")<<newText<<std::endl;  
  57.   
  58.     // 結束   
  59.     std::wcout<<_T("按回車鍵結束...");  
  60.     std::wcin.get();  
  61.     return 0;  
  62. }  
[代碼說明]
1. 創建正則表達式對象,有3中方法:
(1) 使用構造函數
std::regex_constants::syntax_option_type fl = std::regex_constants::icase; // 語法選項,可以設置使用哪種風格的正則表達式語法等.
std::wregex regExpress(regString, fl);
(2) 使用賦值運算符,缺點是不能指定語法選項,而且也比較低效.
std::wregex regExpress;
regExpress = regString;
(3) 使用assign方法.
std::wregex regExpress;
regExpress.assign(regString, fl);
構造正則對象的過稱就是所謂的"編譯".

2. regex_match() 和 regex_search()
regex_match()只有在整個字符串匹配正則表達式時才返回 true, 而 regex_search()在子串匹配就返回 true.

3. 匹配結果對象 std::wsmatch.
熟悉Perl正則表達式的人都知道,匹配成功後可以用 $1 $2 ... $N 來獲得子串的指, tr1 regex庫把匹配結果保存在一個 std::wsmatch(UNICODE) / std::smatch(ANSI) 對象中.
std::wsmatch 是一個由若干個 std::wssub_match 對象構成的數組. 而 std::wssub_match 派生自 pair.
由std::wssub_match::first保存子串的起始位置指針(其實說是迭代器比較准確一點).
由std::wssub_match::second保存子串的結束位置 +1 的指針(STL的通用原則,半開區間).
所以 [std::wssub_match::first,std::wssub_match::second) 就是子串的全部內容.
當然, std::wsmatch (match_result模版的預定義類) 提供了一些簡便的方法用於訪問子串:
(1) str(idx) 方法返回對應的子串的 std::string / std::wstring 對象. 只是最常用的.
(2) position(idx) 方法返回對應子串的起始偏移量.(不是指針,是相對於首字節地址或者begin()的偏移量).
(3) length(idx) 返回子串的長度.

4. 替換子串.
前面說到 std::wssub_match::first / second 保存了子串的起始/結束位置,那麼我們當然可以用這個指針(迭代器)來替換文本(見代碼中的 "替換1").
或者用 std::regex_replace() 也可以達到目的(見代碼中的"替換2").
Copyright © Linux教程網 All Rights Reserved