正则表达式替换为c ++ 11中的回调?

Posted

技术标签:

【中文标题】正则表达式替换为c ++ 11中的回调?【英文标题】:regex replace with callback in c++11? 【发布时间】:2014-03-24 18:04:44 【问题描述】:

是否有正则表达式替换的功能,将匹配发送到用户函数,然后替换返回值:

这个方法我试过了,但是明显不行:

cout << regex_replace("my values are 9, 19", regex("\d+"), my_callback);

和功能:

std::string my_callback(std::string &m) 
  int int_m = atoi(m.c_str());
  return std::to_string(int_m + 1);

结果应该是:my values are 10, 20

我的意思是类似 phppreg_replace_callback 或 python 的 re.sub(pattern, callback, subject) 的工作模式

我的意思是最新的 4.9 gcc,它能够在没有提升的情况下进行正则表达式。

【问题讨论】:

【参考方案1】:

我想要这种功能,但不喜欢“使用增强”的答案。本杰明的答案的问题是它提供了所有的令牌。这意味着您不知道哪个令牌是匹配的,并且它不允许您使用捕获组。这样做:

// clang++ -std=c++11 -stdlib=libc++ -o test test.cpp
#include <cstdlib>
#include <iostream>
#include <string>
#include <regex>

namespace std


template<class BidirIt, class Traits, class CharT, class UnaryFunction>
std::basic_string<CharT> regex_replace(BidirIt first, BidirIt last,
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f)

    std::basic_string<CharT> s;

    typename std::match_results<BidirIt>::difference_type
        positionOfLastMatch = 0;
    auto endOfLastMatch = first;

    auto callback = [&](const std::match_results<BidirIt>& match)
    
        auto positionOfThisMatch = match.position(0);
        auto diff = positionOfThisMatch - positionOfLastMatch;

        auto startOfThisMatch = endOfLastMatch;
        std::advance(startOfThisMatch, diff);

        s.append(endOfLastMatch, startOfThisMatch);
        s.append(f(match));

        auto lengthOfMatch = match.length(0);

        positionOfLastMatch = positionOfThisMatch + lengthOfMatch;

        endOfLastMatch = startOfThisMatch;
        std::advance(endOfLastMatch, lengthOfMatch);
    ;

    std::regex_iterator<BidirIt> begin(first, last, re), end;
    std::for_each(begin, end, callback);

    s.append(endOfLastMatch, last);

    return s;


template<class Traits, class CharT, class UnaryFunction>
std::string regex_replace(const std::string& s,
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f)

    return regex_replace(s.cbegin(), s.cend(), re, f);


 // namespace std

using namespace std;

std::string my_callback(const std::smatch& m) 
  int int_m = atoi(m.str(0).c_str());
  return std::to_string(int_m + 1);


int main(int argc, char *argv[])

    cout << regex_replace("my values are 9, 19", regex("\\d+"),
        my_callback) << endl;

    cout << regex_replace("my values are 9, 19", regex("\\d+"),
        [](const std::smatch& m)
            int int_m = atoi(m.str(0).c_str());
            return std::to_string(int_m + 1);
        
    ) << endl;

    return 0;

【讨论】:

+1 表示解决方案,但您需要使用std 以外的命名空间。目前你的例子有undefined behavior,因为你重载 std::regex_replace,而不是专门化它。 @andree 是正确的 - 假设您从不打算将 std::regex_replace 与字符串替换一起使用,此解决方案很有帮助;否则,编译器会因为歧义而抛出错误。【参考方案2】:

您可以使用regex_token_iterator

#include <iostream>
#include <algorithm>
#include <regex>
#include <string>
#include <sstream>

int main()

    std::string input_text = "my values are 9, 19";
    std::string output_text;
    auto callback = [&](std::string const& m)
        std::istringstream iss(m);
        int n;
        if(iss >> n)
        
            output_text += std::to_string(n+1);
        
        else
        
            output_text += m;
        
    ;

    std::regex re("\\d+");
    std::sregex_token_iterator
        begin(input_text.begin(), input_text.end(), re, -1,0),
        end;
    std::for_each(begin,end,callback);

    std::cout << output_text;

请注意,迭代器构造函数的参数列表中的-1,0 是一个指定我们要迭代的子匹配的列表。 -1 用于不匹配的部分,0 用于第一个子匹配。

另外请注意,我没有广泛使用 c++11 正则表达式功能,也不是这方面的专家。所以这段代码可能有问题。但是对于您的具体输入,我对其进行了测试,它似乎产生了预期的结果。如果您发现任何输入集不起作用,请告诉我。

【讨论】:

它有效。但我认为 Boost 是一个更好的解决方案。 ***.com/questions/11508798/…【参考方案3】:

也许我来得太晚了(大约 5 年的想法),但我不喜欢“使用提升”的答案,以下函数的泛化程度较低(谈到字符串类型),但显然有效。但是,我不知道使用std::ostringstream 是否比std::string::append 更好:

std::string regex_replace(
    const std::string& input,
    const std::regex& regex, 
    std::function<std::string(std::smatch const& match)> format) 

    std::ostringstream output;
    std::sregex_iterator begin(input.begin(), input.end(), regex), end;
    for(; begin != end; begin++)
        output << begin->prefix() << format(*begin);
    
    output << input.substr(input.size() - begin->position());
    return output.str();

所以,如您所见,我使用了std::sregex_iterator 而不是std::sregex_token_iterator

【讨论】:

我不太了解 C++ 标准,但 std::function&lt;std::string(std::smatch const&amp; match)&gt; 是一个可以在其他地方使用的函数 def,就像格式指向的任何内容一样? 我写c++(旧标准)已经很长时间了,我无法忍受看到大括号和代码在同一行......只有我! 嗨,zatarain,一个好主意,但它并没有开箱即用。如果匹配在字符串的开头,这似乎会产生问题。我尝试添加一个单独的索引整数,它在 for 循环中作为最后一条语句更新:subStrStartIndex = begin-&gt;position() + begin-&gt;length()。你可以将它用于 for 循环中的输出流:output &lt;&lt; input.substr(subStrStartIndex, begin-&gt;position() - subStrStartIndex) &lt;&lt; format(*begin); 并且避免在 for 循环之外取消引用 begin,这应该不再有效:output &lt;&lt; input.substr(subStrStartIndex); 这不起作用。当begin == end时,你不能打电话给begin-&gt;position()【参考方案4】:

这种功能只存在于 regex_replace 的 Boost 库版本中,它可以具有自定义格式化程序。不幸的是,标准 C++11 实现要求替换格式参数必须是字符串。

这里是关于 regex_replace 的文档:http://www.cplusplus.com/reference/regex/match_replace/

【讨论】:

以上是关于正则表达式替换为c ++ 11中的回调?的主要内容,如果未能解决你的问题,请参考以下文章

如何将正则表达式参数传递给 PHP 中的 preg 替换回调?

[C/C++11]_[初级]_[使用正则表达式库regex]

MariaDB 中的正则表达式替换

R: 正则表达式

C ++正则表达式替换第一个匹配项

如何同时进行 Typescript 正则表达式替换和提取值?