Первый случай - это действительно сценарий, в котором регулярное выражение C ++ не вполне способно обрабатывать «из коробки» из-за того, что вам нужно заменить захват в группе 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 .