boost——正则表达式

前面一篇文章《编程思想之正则表达式》中讲了正则表达式的编程思想和各种语言下的使用,我们都知道C++标准库自带的正则表达式非常难用,而boost对一个功能进行了拓展,前面一篇文章《boost——入门指南》讲了boost使用环境的配制和入门指南,这篇文章将进一步说说boost中正则表达式的使用,如果您还未搭建好boost的使用环境,请参见《boost——入门指南》。

 

 

本来还想自己写这篇文章来着,但是看到网上已经有同仁写了相同主题的文章,而且写的非常好,我就没有必要重复造轮胎了。 现将这位同仁的博文贴至如下:

原文:http://www.cppblog.com/ming81/archive/2011/05/04/145686.html



注意使用Boost.Regex需要预先编译

完整编译请参考本站 编译Boost的文章
如果只要编译Regex库,有两种方法(参考链接):
  1. 在Boost根目录下运行bjam --toolset=<编译器名> --with-regex 其它参数
  2. \libs egex\build里,找到对应编译器的makefile,然后make -f xxxx.mak

使用

Boost.Regex手里有七种武器和两****宝
其中的七种武器是:
regex_match 函数
regex_search 函数
regex_replace 函数
regex_format 函数
regex_grep 函数
regex_split 函数
RegEx 类
每种武器都又有诸多变化( 每个函数都分别以C字符串类型std::string类型迭代器类型作为参数重载 ),不过后面四种武器因年久失修已不建议使用.
两****宝是:
regex_iterator 迭代器
regex_token_iterator 迭代器
这两****宝是整个Boost.Regex的灵魂,用熟它们以后那是“摘花飞叶即可伤人”啊~~

回到正题,下面边写边学。

所需头文件:

#include 
 

示例代码:

先准备一个测试用的数据备用,如果各位有雅兴可以参考本站的另一篇文章《 Google Testing 》使用Google Testing框架来做这个实验,花一样时间学两样啊~~
  1. #include 
  2. #include 
  3.  
  4. using namespace std;
  5. int main(int argc, char* argv[])
  6. {    //( 1 )   ((  3  )  2 )((  5 )4)(    6    )   
  7.     //(\w+)://((\w+\.)*\w+)((/\w*)*)(/\w+\.\w+)?
  8.     //^协议://网址(x.x...x)/路径(n个\字串)/网页文件(xxx.xxx)
  9.     const char *szReg = "(\\w+)://((\\w+\\.)*\\w+)((/\\w*)*)(/\\w+\\.\\w+)?";
  10.     const char *szStr = "http://www.cppprog.com/2009/0112/48.html";
  11.  
  12.     //练习代码...
  13.    
  14.    
  15.     cin.get(); //暂停
  16. }

1.字符串匹配

要确定一行字符串是否与指定的正则表达式匹配,使用 regex_match
下面这个代码可以验证szStr字串(定义在上面)是否与szReg匹配。
  1. {    //字符串匹配
  2.     boost::regex reg( szReg );
  3.     bool r=boost::regex_match( szStr , reg);
  4.     assert(r); //是否匹配
  5. }

boost::regex 的构造函数中还可以加入标记参数用于指定它的行为,如:
  1. //指定使用perl语法(默认),忽略大小写。
  2. boost::regex reg1( szReg, boost::regex::perl|boost::regex::icase );
  3. //指定使用POSIX扩展语法(其实也差不多)
  4. boost::regex reg2( szReg, boost::regex::extended );


下面这个代码不仅验证是否匹配,而且可以从中提取出正则表达式括号对应的子串。
  1. {    //提取子串
  2.     boost::cmatch mat;
  3.     boost::regex reg( szStr );
  4.     bool r=boost::regex_match( szStr, mat, reg);
  5.     if(r) //如果匹配成功
  6.     {
  7.         //显示所有子串
  8.         for(boost::cmatch::iterator itr=mat.begin(); itr!=mat.end(); ++itr)
  9.         {
  10.             //       指向子串对应首位置        指向子串对应尾位置          子串内容
  11.             cout << itr->first-szStr << ' ' << itr->second-szStr << ' ' << *itr << endl;
  12.         }
  13.     }
  14.     //也可直接取指定位置信息
  15.     if(mat[4].matched) cout << "Path is" << mat[4] << endl;
  16. }

其中, boost::cmatch 是一个针对 C字符串 的特化版本,它还有另三位兄弟,如下:
typedef match_results cmatch;
typedef match_results smatch;
typedef match_results wcmatch;
typedef match_results wsmatch;

可以把 match_results 看成是一个 sub_match 的容器,同时它还提供了 format 方法来代替 regex_format 函数。
一个 sub_match 就是一个子串,它从 std::pair 继承而来,这个 迭代器pair 里的 first second 分别指向了这个子串开始和结尾所在位置。同时, sub_match 又提供了 str(),length() 方法来返回整个子串。
 

2.查找字符串

regex_match 只验证是否完全匹配,如果想从一大串字符串里找出匹配的一小段字符串( 比如从网页文件里找超链接 ),这时就要使用 regex_search 了。
下面这段代码从szStr中找数字
  1. //查找
  2.     boost::cmatch mat;
  3.     boost::regex reg( "\\d+" );    //查找字符串里的数字
  4.     if(boost::regex_search(szStr, mat, reg))
  5.     {
  6.         cout << "searched:" << mat[0] << endl;
  7.     }
  8. }
 

3.替换

regex_replace 提供了简便的方法来部分替换源字符串
正则表达式中,使用 $1~$9 \1~\9 )表示第几个子串, $& 表示整个串, $` 表示第一个串, $' 表示最后未处理的串。
  1. //替换1,把上面的HTTP的URL转成FTP的
  2.     boost::regex reg( szReg );
  3.     string s = boost::regex_replace( string(szStr), reg, "ftp://$2$5");
  4.     cout << "ftp site:"<< s << endl;
  5. }

正则表达式中,使用 (?1~?9新字串) 表示把第几个子串替换成新字串,其中是S1()代表一个字串,S2的(?1)代表替换哪个字串,?0代表所有都要加上后面的字符串?1代表第一个替换成的字符串
  1. //替换2,使用format_all参数把<>&全部转换成网页字符
  2.     string s1 = "(<)|(>)|(&)";
  3.     string s2 = "(?1<)(?2>)(?3&)";
  4.     boost::regex reg( s1 );
  5.     string s = boost::regex_replace( string("cout << a&b << endl;"), reg, s2, boost::match_default | boost::format_all);
  6.     cout << "HTML:"<< s << endl;
  7. }

 

4.使用regex_iterator查找

    对应于C字符串和C++字符串以及宽字符, regex_iterator同样也有四个特化:
    typedef regex_iterator cregex_iterator;
    typedef regex_iterator sregex_iterator;
    typedef regex_iterator wcregex_iterator;
    typedef regex_iterator wsregex_iterator;

    这个迭代器的 value_type定义是一个 match_results
  1. //使用迭代器找出所有数字
  2.     boost::regex reg( "\\d+" );    //查找字符串里的数字
  3.     boost::cregex_iterator itrBegin(szStr, szStr+strlen(szStr), reg);
  4.     boost::cregex_iterator itrEnd;
  5.     for(boost::cregex_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  6.     {
  7.             //       指向子串对应首位置        指向子串对应尾位置          子串内容
  8.             cout << (*itr)[0].first-szStr << ' ' << (*itr)[0].second-szStr << ' ' << *itr << endl;
  9.     }
  10. }

    Boost.Regex也提供了 make_regex_iterator函数简化 regex_iterator的构造,如上面的 itrBegin可以写成:
itrBegin = make_regex_iterator(szStr,reg);
 

5.使用regex_token_iterator拆分字符串

    它同样也有四个特化,形式和上面类似,就不再写一遍骗篇幅了。
    这个迭代器的 value_type定义是一个 sub_match
  1. //使用迭代器拆分字符串
  2.     boost::regex reg("/");  //按/符拆分字符串
  3.     boost::cregex_token_iterator itrBegin(szStr, szStr+strlen(szStr), reg,-1);
  4.     boost::cregex_token_iterator itrEnd;
  5.     for(boost::cregex_token_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  6.     {
  7.         cout << *itr << endl;
  8.     }
  9. }

    Boost.Regex也提供了 make_regex_token_iterator函数简化 regex_token_iterator的构造,最后的那个参数 -1表示以 reg为分隔标志拆分字符串,如果不是-1则表示取第几个子串,并且可以使用数组来表示同时要取几个子串,例如:
  1. //使用迭代器拆分字符串2
  2.     boost::regex reg("(.)/(.)");  //取/的前一字符和后一字符(这个字符串形象貌似有点邪恶-_-)
  3.     int subs[] = {1,2};        // 第一子串和第二子串
  4.     boost::cregex_token_iterator itrBegin = make_regex_token_iterator(szStr,reg,subs); //使用-1参数时拆分,使用其它数字时表示取第几个子串,可使用数组取多个串
  5.     boost::cregex_token_iterator itrEnd;
  6.     for(boost::cregex_token_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  7.     {
  8.         cout << *itr << endl;
  9.     }
  10. }

完整测试代码:

  1. #include 
  2. #include 
  3.  
  4. using namespace std;
  5. int main(int argc, char* argv[])
  6. {    //( 1 )   ((  3  )  2 )((  5 )4)(    6    )   
  7.     //(\w+)://((\w+\.)*\w+)((/\w*)*)(/\w+\.\w+)?
  8.     //^协议://网址(x.x...x)/路径(n个\字串)/网页文件(xxx.xxx)
  9.     const char *szReg = "(\\w+)://((\\w+\\.)*\\w+)((/\\w*)*)(/\\w+\\.\\w+)?";
  10.     const char *szStr = "http://www.cppprog.com/2009/0112/48.html";
  11.  
  12.     {    //字符串匹配
  13.         boost::regex reg( szReg );
  14.         bool r=boost::regex_match( szStr , reg);
  15.         assert(r);
  16.     }
  17.  
  18.     {    //提取子串
  19.         boost::cmatch mat;
  20.         boost::regex reg( szReg );
  21.         bool r=boost::regex_match( szStr, mat, reg);
  22.         if(r) //如果匹配成功
  23.         {
  24.             //显示所有子串
  25.             for(boost::cmatch::iterator itr=mat.begin(); itr!=mat.end(); ++itr)
  26.             {
  27.                 //       指向子串对应首位置        指向子串对应尾位置          子串内容
  28.                 cout << itr->first-szStr << ' ' << itr->second-szStr << ' ' << *itr << endl;
  29.             }
  30.         }
  31.         //也可直接取指定位置信息
  32.         if(mat[4].matched) cout << "Path is" << mat[4] << endl;
  33.     }
  34.  
  35.     { //查找
  36.         boost::cmatch mat;
  37.         boost::regex reg( "\\d+" );    //查找字符串里的数字
  38.         if(boost::regex_search(szStr, mat, reg))
  39.         {
  40.             cout << "searched:" << mat[0] << endl;
  41.         }
  42.     }
  43.  
  44.     { //替换
  45.         boost::regex reg( szReg );
  46.         string s = boost::regex_replace( string(szStr), reg, "ftp://$2$5");
  47.         cout << "ftp site:"<< s << endl;
  48.     }
  49.     { //替换2,把<>&转换成网页字符
  50.         string s1 = "(<)|(>)|(&)";
  51.         string s2 = "(?1<)(?2>)(?3&)";
  52.         boost::regex reg( s1 );
  53.         string s = boost::regex_replace( string("cout << a&b << endl;"), reg, s2, boost::match_default | boost::format_all);
  54.         cout << "HTML:"<< s << endl;
  55.     }
  56.  
  57.     { //使用迭代器找出所有数字
  58.         boost::regex reg( "\\d+" );    //查找字符串里的数字
  59.         boost::cregex_iterator itrBegin = make_regex_iterator(szStr,reg); //(szStr, szStr+strlen(szStr), reg);
  60.         boost::cregex_iterator itrEnd;
  61.         for(boost::cregex_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  62.         {
  63.                 //       指向子串对应首位置        指向子串对应尾位置          子串内容
  64.                 cout << (*itr)[0].first-szStr << ' ' << (*itr)[0].second-szStr << ' ' << *itr << endl;
  65.         }
  66.     }
  67.  
  68.     { //使用迭代器拆分字符串
  69.         boost::regex reg("/");  //按/符拆分字符串
  70.         boost::cregex_token_iterator itrBegin = make_regex_token_iterator(szStr,reg,-1); //使用-1参数时拆分,使用其它数字时表示取第几个子串,可使用数组取多个串
  71.         boost::cregex_token_iterator itrEnd;
  72.         for(boost::cregex_token_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  73.         {
  74.             cout << *itr << endl;
  75.         }
  76.     }
  77.  
  78.     { //使用迭代器拆分字符串2
  79.         boost::regex reg("(.)/(.)");  //取/的前一字符和后一字符(这个字符串形象貌似有点邪恶-_-)
  80.         int subs[] = {1,2};        // 第一子串和第二子串
  81.         boost::cregex_token_iterator itrBegin = make_regex_token_iterator(szStr,reg,subs); //使用-1参数时拆分,使用其它数字时表示取第几个子串,可使用数组取多个串
  82.         boost::cregex_token_iterator itrEnd;
  83.         for(boost::cregex_token_iterator itr=itrBegin; itr!=itrEnd; ++itr)
  84.         {
  85.             cout << *itr << endl;
  86.         }
  87.     }
  88.  
  89.  
  90.     cin.get();
  91.     return 0;
  92. }

你可能感兴趣的:(boost,C++)