【问题标题】:Performing a Regex search and Replace on a std::string在 std::string 上执行正则表达式搜索和替换
【发布时间】:2017-02-11 05:40:33
【问题描述】:

我有一个模式 '"XYZ\d\d' 和一个 'largeish' 字符串,这种模式可以多次出现。

我的目标是在字符串中找到该模式的所有实例,然后将匹配中的所有字符替换为原始字符串中的字母“A”。

到目前为止,我得到了以下信息,但是有一个错误:

#include <iostream>
#include <regex>

int main() {
    std::regex  exp("XYZ\\d\\d");
    std::smatch res;
    std::string str = " XYZ111 d-dxxxxxxx XYZ222 t-nyyyyyyyyy XYZ333 t-r ";

    auto itr = str.cbegin();

    while (std::regex_search(itr, str.cend(), res, exp)) {

        std::cout << "[" << res[0] << "]" << std::endl;

        for (auto j = res[0].first; j != res[0].second; ++j) {
           *j = 'A';  // Error as dereferencing j causes a const reference
        }

        itr += res.position() + res.length();
    }

    std::cout << std::endl;

    std::cout << "mod: " << str << std::endl;

    return 0;
}

我不确定在使用 C++11 regex 工具来完成我的任务时正确的过程是什么。

还想知道是否有像 regex_replace 这样的东西,它需要一个 functor,人们可以在其中指定他们希望如何在每次匹配发生时更改匹配?

【问题讨论】:

  • 搜索"XYZ",然后判断后面是否跟两位数,大概只需要三行代码。对于这样一个简单的匹配,使用正则表达式似乎有点过头了。

标签: c++ regex string c++11 search


【解决方案1】:

由于您有位置和长度,您可以使用它来进行替换,或者如果您只是想摆脱错误,您可以使用非常量迭代器实例化 std::match_results(所有 stdlib 默认实例化都使用 const )。

#include <iostream>
#include <regex>

int main() {
    using strmatch = std::match_results<std::string::iterator>;

    std::regex  expr("XYZ\\d\\d");
    strmatch res;
    std::string str = " XYZ111 d-dxxxxxxx XYZ222 t-nyyyyyyyyy XYZ333 t-r ";

    auto itr = str.begin();

    while (std::regex_search(itr, str.end(), res, expr)) {

        std::cout << "[" << res[0] << "]" << std::endl;

        for (auto j = res[0].first; j != res[0].second; ++j) {
           *j = 'A';  // Error as dereferencing j causes a const reference
        }

        itr += res.position() + res.length();
    }

    std::cout << std::endl;

    std::cout << "mod: " << str << std::endl;

    return 0;
}

【讨论】:

    【解决方案2】:

    您需要一个基于全局正则表达式的替换。这里有三种方法可以在没有任何显式循环的情况下执行此操作(确保正则表达式替换代码中有“隐式”循环):

    #include <iostream>
    #include <string>
    #include <regex> // std::regex
    #include <pcrecpp.h> // pcrecpp::RE -- needs "-lpcrecpp -lpcre"
    #include <pcrscpp.h> // pcrscpp::replace -- needs "-lpcrscpp -lpcre"
    
    int main() {
        std::regex std_rx (R"del(XYZ\d\d)del");
        pcrecpp::RE pcrecpp_rx (R"del(XYZ\d\d)del");
        pcrscpp::replace pcrscpp_rs(R"del(s/XYZ\d\d/A/g)del");
        std::string str = " XYZ111 d-dxxxxxxx XYZ222 t-nyyyyyyyyy XYZ333 t-r ";
    
        std::cout << "std::regex way: " << std::regex_replace (str, std_rx, "A") << std::endl
                  << "pcrecpp way: ";
    
        std::string buffer(str);
        pcrecpp_rx.GlobalReplace("A", &buffer);
    
        std::cout << buffer << std::endl
                  << "pcrscpp way: ";
    
        pcrscpp_rs.replace_store(str);
        std::cout << pcrscpp_rs.replace_result << std::endl;
    
        return 0;
    }
    

    结果:

    std::regex way:  A1 d-dxxxxxxx A2 t-nyyyyyyyyy A3 t-r
    pcrecpp way:  A1 d-dxxxxxxx A2 t-nyyyyyyyyy A3 t-r
    pcrscpp way:  A1 d-dxxxxxxx A2 t-nyyyyyyyyy A3 t-r
    

    std::regex 需要 C++11 功能,并且在简单模式上的执行速度比 PCRE 慢两倍(请参阅this answer),我预计在更复杂的模式上会更糟,但不需要任何额外的库,只要当您使用 C++11 编译器时。 PCRECPP 是由 Google 编写的 PCRE C++ 包装器。 PCRSCPP 是我对 PCRE 的封装,它提供了类似 Perl 的基于正则表达式的替换功能,因此在这个范围内比 PCRECPP 功能丰富得多。

    【讨论】:

      猜你喜欢
      • 2013-06-14
      • 2018-05-25
      • 2010-11-25
      • 2010-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多