前 8 篇在這裡:
- 《C++11 新特性之新型別與初始化》
- 《C++11 新特性之型別推斷與型別獲取》
- 《C++11 新特性之 lambda》
- 《C++11 新特性之容器相關特性》
- 《C++11 新特性之智慧指標》
- 《C++11 新特性之 Class》
- 《C++ 11 新特性之右值引用與移動》
- 《C++ 11 新特性之 template》
這是C++11新特性介紹的第九部分,涉及到正規表示式相關的新特性。
不想看toy code的讀者可以直接拉到文章最後看這部分的總結。
題外話
對regex的完整支援,直到g++4.9才算完善。我使用的系統是Ubuntu14.04,預設g++版本號是4.8.x,所以有一些regex功能無法編譯通過。可以通過以下方法安裝g++4.9:
1 2 3 |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt=get install gcc-4.9 g++-4.9 c++-4.9 |
安裝完成之後,需要在Makefile中強制指定所使用的g++版本。
1 |
CXX=g++-4.9 |
簡單用法
一切就緒,先看看如何用C++11中的regex匹配一個電子郵箱地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
std::cout<<"test regex simple usage:\n"; std::string email_pattern("(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w+)+)"); try { std::regex email_regex(email_pattern); std::smatch results; std::string test_email_str = "My email is yubo1911@163.com"; if(std::regex_search(test_email_str, results, email_regex)) { std::cout<<results.str()<<std::endl; } } catch (std::regex_error e) { std::cout<<e.what()<<'\t'<<e.code()<<std::endl; } std::cout<<"test regex simple usage done.\n"<<std::endl; |
C++中的regex預設使用ECMA-262正規表示式規範,這也是眾多瀏覽器所使用的標準。
注意到email_pattern中有好多雙斜線,這是因為除了regex模組要做一次轉義解析外,C++ string也會對字串做一次轉義解析。
regex選項
在構造regex物件時,可以指定多種標識已實現特定的效果。這裡以使用regex::icase達到不區分大小寫的匹配為例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
std::cout<<"test regex icase:\n"; try { std::regex cpp_regex("(\\w)+\\.(cpp|hpp)$", std::regex::icase); std::vector<std::string> test_filenames = {"regex.cpp", "iostream.h", "template.CPP", "class.hPP", "Ah, regex.cpp", "regex.cpp Ah"}; for(auto fn : test_filenames) { if(std::regex_match(fn, cpp_regex)) { std::cout<<"cpp file: "<<fn<<'\n'; } } } catch (std::regex_error e) { std::cout<<e.what()<<'\t'<<e.code()<<std::endl; } std::cout<<"test regex icase done.\n"<<std::endl; |
regex iterator
regex提供了一個迭代器,這個迭代器生成時需要一個所搜尋字串的範圍以及一個regex物件。之後,迭代器在迭代時,會遍歷搜尋字串中的所有匹配位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
std::cout<<"test regex iterator usage:\n"; try { std::regex email_regex(email_pattern); std::string test_email_str = "I have three emails, yubo1911@163.com, yubo@gmail.com and guoyubo@gmail.com."; for(std::sregex_iterator it(std::begin(test_email_str), std::end(test_email_str), email_regex), end_it; it != end_it; it++) { std::cout<<it->str()<<std::endl; } } catch (std::regex_error e) { std::cout<<e.what()<<'\t'<<e.code()<<std::endl; } std::cout<<"test regex iterator usage done.\n"<<std::endl; |
子表示式
regex也支援子表示式,和其他正規表示式一樣,使用括號括起來的構成一個子表示式。在匹配結果中,序號0表示整個匹配結果,序號1表示子表示式1的匹配結果……
下面以一個座機電話號碼的匹配驗證為例,說明子表示式的運用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
std::cout<<"test regex sub_match usage:\n"; std::string phone_pattern = "(\\()?(\\d{3,4})(\$$)?([- ])?(\\d{7,8})"; try { std::regex phone_regex(phone_pattern); std::smatch results; std::vector<std::string> test_phones = {"010-82224567", "(010-83332345", "(020)62334567", "(021) 22346543", "0357-4223456", "0358-465788"}; for(auto fn : test_phones) { if(std::regex_match(fn, results, phone_regex)) { if(results[1].matched) { if(!results[3].matched) continue; if(results[4].matched && results[4].str() == "-") continue; } else { if(results[3].matched) continue; if(!(results[4].matched && results[4].str() == "-")) continue; } std::cout<<results.str()<<std::endl; } } } catch (std::regex_error e) { std::cout<<e.what()<<'\t'<<e.code()<<std::endl; } std::cout<<"test regex sub_match usage done.\n"<<std::endl; |
replace
regex同樣提供了替換功能。將替換功能和子表示式結合起來,可以實現字串的格式化功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
std::cout<<"test regex replace usage:\n"; try { std::string format = "$2-$5"; std::regex phone_regex(phone_pattern); std::string ori_phone = "yubo: (020)85776452"; std::cout<<"formated phone: "<<std::regex_replace(ori_phone, phone_regex, format) <<std::endl; } catch (std::regex_error e) { std::cout<<e.what()<<'\t'<<e.code()<<std::endl; } std::cout<<"test regex replace usage done.\n"<<std::endl; |
其中format字串中$2和$5就分別表示第二個子表示式和第5個子表示式。
輸出
整個測試程式的輸出結果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
test regex simple usage: yubo1911@163.com test regex simple usage done. test regex icase: cpp file: regex.cpp cpp file: template.CPP cpp file: class.hPP test regex icase done. test regex iterator usage: yubo1911@163.com yubo@gmail.com guoyubo@gmail.com test regex iterator usage done. test regex sub_match usage: 010-82224567 (020)62334567 (021) 22346543 0357-4223456 test regex sub_match usage done. test regex replace usage: formated phone: yubo: 020-85776452 test regex replace usage done. |
總結
- C++11種提供了regex模組,需要g++-4.9以上才能完整支援。
- regex預設採用ECMA-262標準,和瀏覽器中使用的一樣。
- regex提供了查詢、匹配、迭代器、子表示式、替換等常用用法。
完整程式碼詳見regex.cpp
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式