2

I am using std::regex and need to do a search and replace.

The string I have is:

begin foo even spaces and maybe new line(
some text only replace foo foo bar foo, keep the rest
)
some more text not replace foo here

Only the stuff between begin .... ( and ) should be touched.

I manage to replace the first foo by using this search and replace:

(begin[\s\S]*?\([\s\S]*?)foo([\s\S]*?\)[\s\S]*)

$1abc$2

Online regex demo

Online C++ demo

However, how do I replace all three foo in one pass? I tried lookarounds, but failed because of the quantifiers.

The end result should look like this:

begin foo even spaces and maybe new line(
some text only replace abc abc bar abc, keep the rest
)
some more text not replace foo here

Question update:

I am looking for a pure regex solution. That is, the question should be solved by only changing the search and replace strings in the online C++ demo.

Mathias
  • 1,446
  • 2
  • 16
  • 31

1 Answers1

0

I have come up with this code (based on Benjamin Lindley's answer):

#include <iostream>
#include <regex>
#include <string>
int main()
{
    std::string input_text = "my text\nbegin foo even 14 spaces and maybe \nnew line(\nsome text only replace foo foo bar foo, keep the rest\n)\nsome more text not replace foo here";
    std::regex re(R"((begin[^(]*)(\([^)]*\)))");
    std::regex rxReplace(R"(\bfoo\b)");
    std::string output_text;
    auto callback = [&](std::string const& m){
        std::smatch smtch;
        if (regex_search(m, smtch, re)) {
            output_text += smtch[1].str();
            output_text += std::regex_replace(smtch[2].str().c_str(), rxReplace, "abc");
        } else {
            output_text += m;
        }
    };

    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;
    return 0;
}

See IDEONE demo

I am using one regex to find all matches of begin...(....) and pass them into the callback function where only Group 2 is processed further (a \bfoo\b regex is used to replace foos with abcs).

I suggest using (begin[^(]*)(\([^)]*\)) regex:

  • (begin[^(]*) - Group 1 matching a character sequence begin followed with zero or more characters other than (
  • (\([^)]*\)) - Group 2 matching a literal ( followed with zero or more characters other than ) (with [^)]*) and a literal ).
Community
  • 1
  • 1
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Hi, thanks. I am looking for a pure regexp solution. I already worked around this in code, but I would prefer to have all logic in one regex. I'll update my question to make it clearer. But nice solution anyway! – Mathias Jan 27 '16 at 22:59
  • It is not possible to do with std::regex. It does not support \G operator, nor does it support an infinite width lookbehind. – Wiktor Stribiżew Jan 28 '16 at 06:37