正则表达式替换为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
我的意思是类似 php 的 preg_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<std::string(std::smatch const& match)>
是一个可以在其他地方使用的函数 def,就像格式指向的任何内容一样?
我写c++(旧标准)已经很长时间了,我无法忍受看到大括号和代码在同一行......只有我!
嗨,zatarain,一个好主意,但它并没有开箱即用。如果匹配在字符串的开头,这似乎会产生问题。我尝试添加一个单独的索引整数,它在 for 循环中作为最后一条语句更新:subStrStartIndex = begin->position() + begin->length()
。你可以将它用于 for 循环中的输出流:output << input.substr(subStrStartIndex, begin->position() - subStrStartIndex) << format(*begin);
并且避免在 for 循环之外取消引用 begin
,这应该不再有效:output << input.substr(subStrStartIndex);
这不起作用。当begin == end
时,你不能打电话给begin->position()
【参考方案4】:
这种功能只存在于 regex_replace 的 Boost 库版本中,它可以具有自定义格式化程序。不幸的是,标准 C++11 实现要求替换格式参数必须是字符串。
这里是关于 regex_replace 的文档:http://www.cplusplus.com/reference/regex/match_replace/
【讨论】:
以上是关于正则表达式替换为c ++ 11中的回调?的主要内容,如果未能解决你的问题,请参考以下文章
如何将正则表达式参数传递给 PHP 中的 preg 替换回调?