一、简介:

        本文主要是大致的介绍如何使用 C++ 标准库中 std::regex 相关类库,用来打发下无聊的时间。

        在使用 C++ 标准库正则表达式之前,肯定是要先学习正则表达式语法的,不解释。

        要学习正则表达式语法,你百度一下,可以百度一把大。但是,我个人觉得写的最经典的莫过于这篇文章了 正则表达式30分钟入门教程 ,感谢这篇文章作者 30 秒。我觉得只需要读懂这篇文章的 80%,你将感受到正则表达式处理字符串那毁天灭地的威力。

 

二、常用 C++ 标准库正则表达式类:

        C++ 标准库中常用正则表达式类主要包含如下 5 组:

Cpp标准库之 std::regex 类的使用_C++

        有了以上 5 组模板,基本上可以处理所有的字符串处理需求了。

 

三、C++ 正则表达式模板的使用:

        std::regex_match: 正则表达式需要匹配整个字符串序列,也就是说正则表达式要与字符串完全匹配。因此,它是单次匹配,否则匹配失败。

        范例代码如下:

 

  1.  
    void match()
  2.  
    {
  3.  
    /
  4.  
    //std::regex_match
  5.  
    //std::regex_match: 正则表达式需要匹配整个字符串序列, 也就是说正则表达式要与
  6.  
    //字符串完全匹配, 因此, 它是单次匹配, 否则匹配失败.
  7.  
    //此外, 它还可以获取子匹配的组
  8.  
     
  9.  
    std::string text = "Date:2017-10-10";
  10.  
     
  11.  
    //构造正则表达式
  12.  
    //这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
  13.  
    std::string pattern = "Date.(\\d{4})-(\\d{2}-(\\d{2}))";
  14.  
    std::regex express(pattern);
  15.  
     
  16.  
    //匹配
  17.  
    std::cout.setf(std::ios_base::boolalpha);
  18.  
    /*模板函数1-1*/
  19.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
  20.  
    //这里使用的是 std::string::iterator 迭代器, 与 begin()/ end() 返回的迭代器类型(std::string::iterator)要一致
  21.  
    std::match_results<std::string::iterator> results1;
  22.  
    if(std::regex_match(text.begin(), text.end(), results1, express))
  23.  
    {
  24.  
    std::match_results<std::string::iterator>::const_iterator iter;
  25.  
    for (iter = results1.begin(); iter != results1.end(); iter++)
  26.  
    {
  27.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  28.  
    }
  29.  
    }
  30.  
    /*输出
  31.  
    15: Date:2017-10-10
  32.  
    4: 2017
  33.  
    5: 10-10
  34.  
    2: 10
  35.  
    */
  36.  
     
  37.  
    /*模板函数1-2*/
  38.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
  39.  
    //std::smatch == std::match_results<std::string::const_iterator>
  40.  
    std::smatch s_results1;
  41.  
    if(std::regex_match(text.cbegin(), text.cend(), s_results1, express))
  42.  
    {
  43.  
    std::match_results<std::string::const_iterator>::const_iterator iter;
  44.  
    for (iter = s_results1.begin(); iter != s_results1.end(); iter++)
  45.  
    {
  46.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  47.  
    }
  48.  
    }
  49.  
    /*输出
  50.  
    15: Date:2017-10-10
  51.  
    4: 2017
  52.  
    5: 10-10
  53.  
    2: 10
  54.  
    */
  55.  
     
  56.  
    /*模板函数2*/
  57.  
    //显示字符串是否符合正则表达式, 用于检测字符串规则
  58.  
    std::cout << std::regex_match(text.begin(), text.end(), express) << std::endl;
  59.  
     
  60.  
    /*模板函数3*/
  61.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
  62.  
    //std::cmatch == std::match_results<const char*>
  63.  
    std::cmatch c_results3;
  64.  
    if(std::regex_match(text.c_str(), c_results3, express))
  65.  
    {
  66.  
    for (auto iter = c_results3.begin(); iter != c_results3.end(); iter++)
  67.  
    {
  68.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  69.  
    }
  70.  
    }
  71.  
    /*输出
  72.  
    15: Date:2017-10-10
  73.  
    4: 2017
  74.  
    5: 10-10
  75.  
    2: 10
  76.  
    */
  77.  
     
  78.  
    /*模板函数4*/
  79.  
    //显示字符串是否符合正则表达式, 用于检测字符串规则
  80.  
    std::cout << std::regex_match(text.c_str(), express) << std::endl;
  81.  
     
  82.  
    /*模板函数5*/
  83.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
  84.  
    std::match_results<std::string::const_iterator> s_results5;
  85.  
    if(std::regex_match(text, s_results5, express))
  86.  
    {
  87.  
    for (size_t index = 0; index < s_results5.size(); index++)
  88.  
    {
  89.  
    //sub_match: 子匹配, match_results里面都存放的是sub_match
  90.  
    //sub_match 可以理解为 std::pair 的扩展, 它继承了 std::pair,
  91.  
    //其中 first 实际上存放的是获取的字符串头指针地址, second 为尾指针地址
  92.  
    std::ssub_match sub = s_results5[index];
  93.  
    std::cout << sub.length() << ": " << sub.str() << std::endl;
  94.  
    }
  95.  
    }
  96.  
    /*输出
  97.  
    15: Date:2017-10-10
  98.  
    4: 2017
  99.  
    5: 10-10
  100.  
    2: 10
  101.  
    */
  102.  
     
  103.  
    /*模板函数6*/
  104.  
    //显示字符串是否符合正则表达式, 用于检测字符串规则
  105.  
    std::cout << std::regex_match(text, express) << std::endl;
  106.  
    /
  107.  
    }

        std::regex_search: 搜素正则表达式参数,但它不要求整个字符序列完全匹配。而且它只进行单次搜索,搜索到即停止继续搜索,不进行重复多次搜索。

 

        范例代码如下:

 

  1.  
    void search()
  2.  
    {
  3.  
    /
  4.  
    //std::regex_search
  5.  
    //std::regex_search: 搜素正则表达式参数, 但它不要求整个字符序列完全匹配.
  6.  
    //而且它只进行单次搜索, 搜索到即停止继续搜索, 不进行重复多次搜索.
  7.  
     
  8.  
    std::string text = "Date:2017-10-10 ~ 2017-10-15";
  9.  
     
  10.  
    //构造正则表达式
  11.  
    //这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
  12.  
    std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
  13.  
    std::regex express(pattern);
  14.  
     
  15.  
    //匹配
  16.  
    std::cout.setf(std::ios_base::boolalpha);
  17.  
     
  18.  
    /*模板函数1*/
  19.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
  20.  
    std::match_results<std::string::iterator> results1;
  21.  
    if(std::regex_search(text.begin(), text.end(), results1, express))
  22.  
    {
  23.  
    //使用迭代器遍历, 这里的迭代器实际上是指向 std::sub_match 的指针
  24.  
    std::match_results<std::string::iterator>::const_iterator iter;
  25.  
    for (iter = results1.begin(); iter != results1.end(); iter++)
  26.  
    {
  27.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  28.  
    }
  29.  
    }
  30.  
    /*输出
  31.  
    10: 2017-10-10
  32.  
    4: 2017
  33.  
    5: 10-10
  34.  
    2: 10
  35.  
    */
  36.  
     
  37.  
    /*模板函数2*/
  38.  
    //显示是否有搜索到符合正则表达式的结果
  39.  
    std::cout << std::regex_search(text.begin(), text.end(), express) << std::endl;
  40.  
     
  41.  
    /*模板函数3*/
  42.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
  43.  
    std::cmatch c_results3;
  44.  
    if(std::regex_search(text.c_str(), c_results3, express))
  45.  
    {
  46.  
    for (size_t index = 0; index < c_results3.size(); index++)
  47.  
    {
  48.  
    //获取组里面的数据, 注意: 这里使用的是 std::csub_match,
  49.  
    //实际上存放在 std::match_results 里面的数据就是一组 std::sub_match
  50.  
    std::csub_match sub = c_results3[index];
  51.  
     
  52.  
    //先获取长度, 再获取内容
  53.  
    std::cout << sub.length() << ": " << sub.str() << std::endl;
  54.  
    }
  55.  
    }
  56.  
    /*输出
  57.  
    10: 2017-10-10
  58.  
    4: 2017
  59.  
    5: 10-10
  60.  
    2: 10
  61.  
    */
  62.  
     
  63.  
    /*模板函数4*/
  64.  
    //显示是否有搜索到符合正则表达式的结果
  65.  
    std::cout << std::regex_search(text.c_str(), express) << std::endl;
  66.  
     
  67.  
    /*模板函数5*/
  68.  
    //第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
  69.  
    std::smatch s_results5;
  70.  
    if (std::regex_search(text, s_results5, express))
  71.  
    {
  72.  
    for (auto iter = s_results5.begin(); iter != s_results5.end(); iter++)
  73.  
    {
  74.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  75.  
    }
  76.  
    }
  77.  
    /*输出
  78.  
    10: 2017-10-10
  79.  
    4: 2017
  80.  
    5: 10-10
  81.  
    2: 10
  82.  
    */
  83.  
     
  84.  
    /*模板函数6*/
  85.  
    //显示是否有搜索到符合正则表达式的结果
  86.  
    std::cout << std::regex_search(text, express) << std::endl;
  87.  
    }

        std::regex_replace: 多次搜索整个正则表达式(不考虑捕获组),然后替换正则表达式匹配到的结果。

 

        范例代码如下:

 

  1.  
    void replace()
  2.  
    {
  3.  
    /
  4.  
    //std::regex_replace
  5.  
    //std::regex_replace:
  6.  
     
  7.  
    std::string text = "Date:2017-10-10 ~ 2017-10-15";
  8.  
     
  9.  
    //构造正则表达式
  10.  
    //这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
  11.  
    std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
  12.  
    std::regex express(pattern);
  13.  
     
  14.  
    //定义存储结果变量已经替换字符
  15.  
    std::stringresult(256, '0');
  16.  
    std::string substitutes = "2017-10-12";
  17.  
     
  18.  
    /*模板函数1*/
  19.  
    //多次搜索整个正则表达式(不考虑捕获组), 然后替换正则表达式匹配到的结果
  20.  
    //std::regex_replace 模板函数返回值实际上是新的字符串存入变量后尾部的指针位置, 置 0 是为了防止变量数据出错或乱码
  21.  
    *std::regex_replace(result.begin(), text.begin(), text.end(), express, substitutes) = '\0';
  22.  
    std::cout << result.c_str() << std::endl;
  23.  
    /*输出:
  24.  
    Date:2017-10-12 ~ 2017-10-12
  25.  
    */
  26.  
     
  27.  
    result.clear();
  28.  
    result.resize(256, '0');
  29.  
     
  30.  
    /*模板函数2*/
  31.  
    //多次搜索整个正则表达式(不考虑捕获组), 然后替换正则表达式匹配到的结果
  32.  
    //std::regex_replace 模板函数返回值实际上是新的字符串存入变量后尾部的指针位置, 置 0 是为了防止变量数据出错或乱码
  33.  
    result = std::regex_replace(text, express, substitutes);
  34.  
    std::cout << result.c_str() << std::endl;
  35.  
    /*输出:
  36.  
    Date:2017-10-12 ~ 2017-10-12
  37.  
    */
  38.  
    }

        std::regex_iterator: 用于多次重复匹配,不分组,只进行多次匹配整个正则表达式,可获取整个正则表达式的结果。

 

        范例代码如下:

 

  1.  
    void iterator()
  2.  
    {
  3.  
    /
  4.  
    //std::regex_iterator
  5.  
    //std::regex_iterator: 用于多次重复匹配, 不分组, 只进行多次匹配整个正则表达式,
  6.  
    //可获取整个正则表达式的结果
  7.  
     
  8.  
    std::string text = "Date:2017-10-10 ~ 2017-10-15";
  9.  
     
  10.  
    //构造正则表达式
  11.  
    //这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
  12.  
    std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
  13.  
    std::regex express(pattern);
  14.  
     
  15.  
    std::regex_iterator<std::string::const_iterator> begin(text.cbegin(), text.cend(), express);
  16.  
    //std::sregex_iterator == std::regex_iterator<std::string::const_iterator>
  17.  
    for (auto iter = begin; iter != std::sregex_iterator(); iter++)
  18.  
    {
  19.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  20.  
    }
  21.  
    /*输出
  22.  
    10: 2017-10-10
  23.  
    10: 2017-10-15
  24.  
    */
  25.  
    }

        std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式的结果,也可以获取正则表达式的前缀,还可以获取正则表达式的分组子匹配。

 

        范例代码如下:

 

  1.  
    void token_iterator()
  2.  
    {
  3.  
    /
  4.  
    //std::regex_token_iterator
  5.  
    //std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式
  6.  
    //的结果, 也可以获取正则表达式的前缀, 还可以获取正则表达式的分组子匹配
  7.  
     
  8.  
    std::string text = "Date:2017-10-10 ~ 2017-10-15";
  9.  
     
  10.  
    //构造正则表达式
  11.  
    //这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
  12.  
    std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
  13.  
    std::regex express(pattern);
  14.  
     
  15.  
    /*构造函数2-1*/
  16.  
    //(多次匹配)显示正则表达式匹配, 即参数 4 等于 0
  17.  
    std::regex_token_iterator<std::string::const_iterator> begin2_1(text.cbegin(), text.cend(), express);
  18.  
    //std::sregex_token_iterator == std::regex_token_iterator<std::string::const_iterator>
  19.  
    for (auto iter = begin2_1; iter != std::sregex_token_iterator(); iter++)
  20.  
    {
  21.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  22.  
    }
  23.  
    /*输出
  24.  
    10: 2017-10-10
  25.  
    10: 2017-10-15
  26.  
    */
  27.  
     
  28.  
    /*构造函数2-2*/
  29.  
    //(多次匹配)显示正则表达式匹配到的前缀, -1 则表示只显示前缀
  30.  
    std::regex_token_iterator<std::string::const_iterator> begin2_2(text.cbegin(), text.cend(), express, -1);
  31.  
    for (auto iter = begin2_2; iter != std::sregex_token_iterator(); iter++)
  32.  
    {
  33.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  34.  
    }
  35.  
    /*输出
  36.  
    5: Date:
  37.  
    3: ~
  38.  
    */
  39.  
     
  40.  
    /*构造函数2-3*/
  41.  
    //(多次匹配)显示正则表达式子匹配, 3 表示第三组子匹配
  42.  
    std::regex_token_iterator<std::string::const_iterator> begin2_3(text.cbegin(), text.cend(), express, 3);
  43.  
    for (auto iter = begin2_3; iter != std::sregex_token_iterator(); iter++)
  44.  
    {
  45.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  46.  
    }
  47.  
    /*输出
  48.  
    2: 10
  49.  
    2: 15
  50.  
    */
  51.  
     
  52.  
    /*构造函数3*/
  53.  
    //(多次匹配)显示正则表达式匹配到的前缀和子匹配, -1 表示前缀, 2 表示第二个子匹配
  54.  
    std::vector<int> vec;
  55.  
    vec.push_back(-1);
  56.  
    vec.push_back(2);
  57.  
    std::regex_token_iterator<std::string::iterator> begin3(text.begin(), text.end(), express, vec);
  58.  
    for (auto iter = begin3; iter != std::regex_token_iterator<std::string::iterator>(); iter++)
  59.  
    {
  60.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  61.  
    }
  62.  
    /*输出
  63.  
    5: Date:
  64.  
    5: 10-10
  65.  
    3: ~
  66.  
    5: 10-15
  67.  
    */
  68.  
     
  69.  
    /*构造函数4*/
  70.  
    //(多次匹配)显示正则表达式匹配到的前缀和整个正则表达式匹配, -1 表示前缀, 0 表示匹配整个正则表达式.
  71.  
    int arr[] = {-1, 0};
  72.  
    std::regex_token_iterator<std::string::iterator> begin4(text.begin(), text.end(), express, arr);
  73.  
    for (auto iter = begin4; iter != std::regex_token_iterator<std::string::iterator>(); iter++)
  74.  
    {
  75.  
    std::cout << iter->length() << ": " << iter->str() << std::endl;
  76.  
    }
  77.  
    /*输出
  78.  
    5: Date:
  79.  
    10: 2017-10-10
  80.  
    3: ~
  81.  
    10: 2017-10-15
  82.  
    */
  83.  
    }

        主函数:

 

 

  1.  
    int main()
  2.  
    {
  3.  
    search();
  4.  
     
  5.  
    system("pause");
  6.  
    return0;
  7.  
    }

        以上范例及说明基本上已介绍模板的使用方法,其中模板中的 match_flag_type 我没有使用,可以查阅 MSDN 来使用。另,源代码下载地址:std::regex usge demo