C++ 11 新特性之正则表达式

Posted CPP开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 11 新特性之正则表达式相关的知识,希望对你有一定的参考价值。


来源: 伯乐在线专栏作者/usher2007

链接:http://blog.jobbole.com/105466/


前8篇在这里:


  • 《》

  • 《》

  • 《》

  • 《》

  • 《》

  • 《》

  • 《》

  • 《》


这是C++11新特性介绍的第九部分,涉及到正则表达式相关的新特性。


不想看toy code的读者可以直接拉到文章最后看这部分的总结。


题外话


对regex的完整支持,直到g++4.9才算完善。我使用的系统是Ubuntu14.04,默认g++版本号是4.8.x,所以有一些regex功能无法编译通过。可以通过以下方法安装g++4.9:


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++版本。


CXX=g++-4.9


简单用法



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达到不区分大小写的匹配为例。


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对象。之后,迭代器在迭代时,会遍历搜寻字符串中的所有匹配位置。


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的匹配结果……



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同样提供了替换功能。将替换功能和子表达式结合起来,可以实现字符串的格式化功能:


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个子表达式。


输出


整个测试程序的输出结果如下:


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.


总结


  1. C++11种提供了regex模块,需要g++-4.9以上才能完整支持。

  2. regex默认采用ECMA-262标准,和浏览器中使用的一样。

  3. regex提供了查找、匹配、迭代器、子表达式、替换等常用用法。


点击<阅读原文>可以获得完整代码


专栏作者简介   (  )


郭茄茄游戏开发 C/C++ Python Linux

打赏支持作者写出更多好文章,谢谢!




------------------ 推荐 ------------------


范品社推出了十几款程序员、电影、美剧和物理题材的极客T恤单件 ¥59.9、两件减¥12、四件减¥28,详见网店商品页介绍。

淘口令:复制以下红色内容,然后打开手淘即可购买

范品社,使用¥极客T恤¥抢先预览(长按复制整段文案,打开手机淘宝即可进入活动内容)

以上是关于C++ 11 新特性之正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

ES2018 新特征之:正则表达式 dotAll 模式

C++正则表达式之PCRE++

C++正则表达式之PCRE++

ES9的新特性:正则表达式RegExp

C++ 中也能使用的正则表达式

Oracle10g新特性——正则表达式 - 转