0

I am having ridiculous difficulties matching a regex and replacing the match with another string. I want to achieve this with iterators, as outlined below. The part that does not work is getting iterators that delimit the match in the original string and that I could then pass to string::replace. I tried using a std::match_results object to get a pair of iterators, but replacing m by mr in the call of regex_search fails.

I have the vague feeling that I either use the wrong match class or the wrong type of iterator, but somehow can't find my way out of template jungle.

std::string txt{ "aaa bbb" };
std::smatch m;
std::regex rx(R"(aaa)");
std::match_results<std::string::iterator> mr;

if (std::regex_search(cbegin(txt), cend(txt), m, rx)) {
    std::cerr << m[0] << std::endl;

    // what I need here are iterators that I can pass
    // to string::replace

    // txt.replace(i1 ,i2, std::string("ccc"));
}
user52366
  • 1,035
  • 1
  • 10
  • 21

3 Answers3

1

Try this segment

std::string::const_iterator start = txt.begin();
std::string::const_iterator end   = txt.end();

if ( std::regex_search( start, end, m, rx ) ) 

Typical use in while loop

while ( std::regex_search( start, end, m, rx ) )
{
    // do stuff with match
    start = m[0].second;
}
  • 1
    Thanks, that gave me the right idea. m[0].first would be the beginning and m[0].second the end iteratior. – user52366 May 27 '20 at 07:04
1

Why do you want to replace with iterators? You might know this but there is std::regex_replace method that could do this.

std::string stringText{ "aaa bbb" };
std::regex regexMatch("aaa");
std::string stringResult;

std::regex_replace(std::back_inserter(stringResult), std::cbegin(stringText), std::cend(stringText), regexMatch, "ccc");

Another similar sample from a regex tutorial using regex_replace (scroll down a bit)

It is possible to use iterators but then you need to build a new string from current. if you want i can do a sample.

Per Ghosh
  • 449
  • 5
  • 10
  • I was looking exactly for this solution, when I need a huge amount of strings to be processed and this allows `stringResult` to be reused across iterations reducing number of memory allocations. – Simon Rozman Aug 24 '23 at 11:34
0

Thanks to @Edward I realized that m[0] contains a pair of iterators that defines the matching substring. I had tried first and second but on m instead of m[0], which of course failed.

With this the replacement was easy:

std::string txt{ "aaa bbb" };
std::smatch m;
std::regex rx(R"(aaa)");

if (std::regex_search(cbegin(txt), cend(txt), m, rx)) {
    txt.replace(m[0].first, m[0].second, std::string("ccc"));
}
user52366
  • 1,035
  • 1
  • 10
  • 21
  • And with iterators it is possible to construct a regex_replace() with a callback simulation. Using the while loop, you can do this by keeping track of the last match iterator and based on the current segment, `sResult.append( lastend, m[0].first); sResult+= std::string("ccc");` where `lastend = mlast[0].second;` Also in a while loop callback simulation you can keep track of the number of matches, totally control the output and break out of the loop via `break;` or setting `start = end;` See this for example https://stackoverflow.com/questions/22617209/regex-replace-with-callback-in-c11 –  May 27 '20 at 16:48