1

I have a c++ string with embedded '\0' characters.

I have a function replaceAll() which should replace all occurrences of a pattern with another pattern. For "normal" strings it works fine. However, when I try to find the '\0' character my function does not work and I don't know why. replaceAll seems to be failing on string::find() which doesn't make sense to me.

// Replaces all occurrences of the text 'from' to the text 'to' in the specified input string.
// replaceAll("Foo123Foo", "Foo", "Bar"); // Bar123Bar
string replaceAll( string in, string from, string to )
{
    string tmp = in;

    if ( from.empty())
    {
    return in;
    }

    size_t start_pos = 0;

    // tmp.find() fails to match on "\0"
    while (( start_pos = tmp.find( from, start_pos )) != std::string::npos )
    {
    tmp.replace( start_pos, from.length(), to );
        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
    }

    return tmp;
}

int main(int argc, char* argv[])
{
    string stringWithNull = { '\0', '1', '\0', '2' };
    printf("size=[%d] data=[%s]\n", stringWithNull.size(), stringWithNull.c_str());

    // This doesn't work in the special case of a null character and I don't know why
    string replaced = replaceAll(stringWithNull, "\0", "");
    printf("size=[%d] data=[%s]\n", replaced.size(), replaced.c_str());
}

Output:

size=[4] data=[]
size=[4] data=[]
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
LeviX
  • 3,096
  • 3
  • 28
  • 41
  • Did you debug it to see if your loop was really finding the character? – Matthieu Brucher Nov 07 '18 at 15:48
  • BTW, you should actually search for the characters themselves, not strings. – Matthieu Brucher Nov 07 '18 at 15:49
  • @MatthieuBrucher Why search for the characters? That limits the function. If I want to reaplce all occurances of `":)"` from `":) :) :) :::too many smiles::: :) :) :)"` that would be a real pain if I couldn't specify `":)"` as the thing to replace. – NathanOliver Nov 07 '18 at 16:05

2 Answers2

6

The reason why it doesn't work in your case is that std::string constructor from const char* without size is going to read all elements up to, but not including nul-terminating char. As a result,

 replaceAll(stringWithNull, "\0", "");

Calls replaceAll with from set to empty string (replaceAll( string in, string from, string to )), which returns in unmodified.

To solve the problem, use a constructor which takes size, or initialize with list initialization, the same way you do it for your original string, for example:

replaceAll(stringWithNull, {'\0'}, "");
SergeyA
  • 61,605
  • 5
  • 78
  • 137
1

When you do

replaceAll(stringWithNull, "\0", "");

"\0" is the same as "" since std::string's constructor stops at the null character when being constructed from a c-string. That means you are searching for nothing and replacing it with nothing. What you need is

string replaced = replaceAll(stringWithNull, {'\0'}, "");

to actually get from populated with a null character.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402