Std :: regex_replace replaces all other matches?

I need to parse json strings (with boost :: property_tree :: read_json)

Some input lines are not valid as they look like:

"[1,2,3,,,,,4]"

      

when should they look like:

"[1,2,3,null,null,null,null,4]"

      

What is the best way to convert such a string?

I tried

//option A:
std::regex rx1(",,");
auto out_str = std::regex_replace(str_in, rx1, std::string(",null,"));

      

and

//option B:
auto out_str = boost::algorithm::replace_all_copy(str_in, ",,", ",null,");

      

But both options only replace every other match. How in:

"[1,2,3,null,,null,,4]"

      

Basically, I don't want to replace, but to insert the substring. Id to avoid writing characters for which I agree.

Edit:

I would like to avoid consuming and inserting commas. Something like

//option C 
std::regex rx1(",(),"); 
auto out_str = std::regex_replace(str_in, rx1, std::string("null")); 

      

But it doesn't work (maybe because it is the wrong regex syntax)

+3


source to share


5 answers


regex

replaces the search with the first match and then replaces it. No overlap matches are made. So, if he sees ,,,

, he replaces the first two commas with ,null,

giving ,null,,

. But he does not look at what he replaced and what is ahead of the replacement. Stages:

  • Finds the first occurrence: , ,
  • Replaces the first occurrence: , null, ,
  • Moves and sees only one comma, as it only looks at the string after the previous search / replace.


So you are replacing ,,

with ,null,

, but don't look at the comma you used in the replacement string ,null,

because it does not match the matches.

To make sure it does match the matches, just run search twice and replace the string.

+1


source


You really don't need a regex to do such a simple task, a simple search and insert will work:

#include <iostream>
using namespace std;

int main() {
    std::string str{ "[1,2,3,,,,,4]" };
    do {
        auto pos = str.find( ",," );
        if( pos == std::string::npos )
            break;
        str.insert( pos + 1, "null" );
    } while( true );
    std::cout << str << std::endl;
    return 0;
}

      



Run it on ideone

+2


source


Your replacement string is incorrect. Do it manually:

Start: "[1,2,3,,,,,4]"
Replacement 1: "[1,2,3,null,|,,,4]"
                     ^parsed up to here
Repalcement 2: "[1,2,3,null,,null,|,4]"
                                  ^parsed to here, no more matches

      

You either want to adjust your replacement string, or replace it multiple times until the string changes.

+1


source


you can call your function twice (although this is not an optimal solution)

std::string in_str = "[1,2,3,,,,,4]";
std::regex rx1(",,");
auto out_str = std::regex_replace(in_str, rx1, std::string(",null,"));
out_str = std::regex_replace(out_str, rx1, std::string(",null,"));

      

+1


source


you can add a while loop to your B variant:

auto out_str = str_in;

while (out_str.find(",,") != std::string::npos) {
    out_str =  boost::algorithm::replace_all_copy(out_str, ",,", ",null,");
}

      

+1


source







All Articles