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.

4
  • 1
    What should the end result look like? Commented Jan 27, 2016 at 8:22
  • 1
    Maybe it would be easier to get the text between brackets and do a replace all? Then you reconstruct the string. Commented Jan 27, 2016 at 8:52
  • @Thomas there is, read closely. Commented Jan 27, 2016 at 9:19
  • @Revolver_Ocelot damn wrong copy/paste. Thanks. Commented Jan 27, 2016 at 9:20

1 Answer 1

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 ).
Sign up to request clarification or add additional context in comments.

2 Comments

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!
It is not possible to do with std::regex. It does not support \G operator, nor does it support an infinite width lookbehind.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.