[背景介紹]
要想在程序中使用正則表達式,首先需要有庫支持.目前比較有影響的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]
- #include <iostream>
- #include <string>
- #include <regex>
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- std::locale loc("");
- std::wcout.imbue(loc);
-
- std::wstring text(_T("我的IP地址是:109.168.0.1."));
- std::wstring newIP(_T("127.0.0.1"));
- std::wstring regString(_T("(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"));
-
- // 表達式選項 - 忽略大小寫
- std::regex_constants::syntax_option_type fl = std::regex_constants::icase;
-
- // 編譯一個正則表達式語句
- std::wregex regExpress(regString, fl);
-
- // 保存查找的結果
- std::wsmatch ms;
-
- // 判斷是否全行匹配
- if(std::regex_match(text, ms, regExpress))
- {
- std::wcout<<_T("正則表達式:")<<regString<<_T("匹配:")<<text<<_T("成功.")<<std::endl;
- }
- else
- {
- std::wcout<<_T("正則表達式:")<<regString<<_T("匹配:")<<text<<_T("失敗.")<<std::endl;
- }
-
- // 查找
- if(std::regex_search(text, ms, regExpress))
- {
- std::wcout<<_T("正則表達式:")<<regString<<_T("查找:")<<text<<_T("成功.")<<std::endl;
- for(size_t i= 0; i < ms.size(); ++i)
- {
- std::wcout<<_T("第")<<i<<_T("個結果:\"")<<ms.str(i)<<_T("\" - ");
- std::wcout<<_T("起始位置:")<<ms.position(i)<<_T("長度")<<ms.length(i)<<std::endl;
- }
- std::wcout<<std::endl;
-
- // 替換1
- text = text.replace(ms[0].first, ms[0].second, newIP);
- std::wcout<<_T("替換1後的文本:")<<text<<std::endl;
- }
- else
- {
- std::wcout<<_T("正則表達式:")<<regString<<_T("查找:")<<text<<_T("失敗.")<<std::endl;
- }
-
- // 替換2
- newIP = _T("255.255.0.0");
- std::wstring newText = std::regex_replace( text, regExpress, newIP);
- std::wcout<<_T("替換2後的文本:")<<newText<<std::endl;
-
- // 結束
- std::wcout<<_T("按回車鍵結束...");
- std::wcin.get();
- return 0;
- }
[代碼說明]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").