将标签1标签2标签3替换为x1 x2 x3



我对regex和C++很陌生,所以请对我宽容一点:(!


给定这样一个字符串:

输入:

string s = "<ph0/>Hello StackOverflow! Thank you for helping! <ph1/>"

我想分别替换__ent_0000000_和__ent_00001_的ph1和ph2标签,所以最后我希望我的输出是:输出:

string s = "__ent_00000_Hello StackOverflow! Thank you for helping! __ent_00001_"



我也想做相反的事情,即:

输入:

string s = "__ent_00000_Bye bye StackOverflow!  __ent_00001_"

输出:

string s = "<ph0/>Bye bye StackOverflow!  <ph1/>"


这将适用于字符串中任意数量的标签!所以这里的想法是简单地替换,但保持数字不变!

我的想法是regex_replace(文档(,但是也许还有另一种方法,我对任何其他有效的解决方案都持开放态度!


具有多个标签的示例:

输入:

string input = "Restaurant is closed<ph0/> <ph1/> <ph2/> <ph3/> | <ph4/> <ph5/>alert<ph6/>We are not serving meals<ph7/> <ph8/> <ph9/> <ph10/> | <ph11/> <ph12/>sorry!"

输出:

string output = "Restaurant is closed__ent_00000_ __ent_00001_ __ent_00002_ __ent_00003_ | __ent_00004_ __ent_00005_alert__ent_00006_We are not serving meals__ent_00007_ __ent_00008_ __ent_00009_ __ent_00010_ | __ent_00011_ __ent_00012_sorry!"

谢谢你,祝你今天愉快!:(

如果这个问题的第一个解决方案涉及正则表达式,那么您就注定要失败请不要(其中一个简单的字符串替换就足够了(。

如果每个标记只出现一次,那么您真正需要做的就是对它们调用string::replace。即使它们发生多次,使用boost的replace_all()算法。

第一种情况实际上是C++regex无法开箱即用的情况,因为您需要用左零填充数字替换组1中的捕获。它需要回调,可以这样实现:

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::sregex_iterator 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);
}
std::string callback_to(const std::smatch& m) {
stringstream s;
char buffer[6];
sprintf(buffer, "%05d", stoi(m.str(1)));
s << "__ent_" << buffer << "_";
return s.str();
}

然后,在主代码中,您可以像一样使用它

std::string s = "Restaurant is closed<ph0/> <ph1/> <ph2/> <ph3/> | <ph4/> <ph5/>alert<ph6/>We are not serving meals<ph7/> <ph8/> <ph9/> <ph10/> | <ph11/> <ph12/>sorry!";
std::regex reg_to("<ph(\d+)/>");
std::cout << regex_replace(s, reg_to, callback_to) << std::endl;
// => Restaurant is closed__ent_00000_ __ent_00001_ __ent_00002_ __ent_00003_ | __ent_00004_ __ent_00005_alert__ent_00006_We are not serving meals__ent_00007_ __ent_00008_ __ent_00009_ __ent_00010_ | __ent_00011_ __ent_00012_sorry!

正则表达式很简单,<ph(d+)/>,匹配<ph,在组1中捕获1+个数字,然后是/>。在回调方法中,char buffer[6]; sprintf(buffer, "%05d", stoi(m.str(1)));将准备数字,s << "__ent_" << buffer << "_";将获得充满必要数据的字符串蒸汽。

相反的替代方法简单而直接:

std::string t = "__ent_00000_Bye bye StackOverflow!  __ent_00001_";
std::regex reg_from("__ent_0*(\d+)_");
std::cout << std::regex_replace(t, reg_from, "<ph$1/>") << std::endl;
// => <ph0/>Bye bye StackOverflow!  <ph1/>

__ent_0*(d+)_模式匹配__ent_,然后零个或多个0字符,然后将1+个数字捕获到组1中,然后匹配_。替换为<ph+组1值和/>文本。

请参阅regex演示。

最新更新