Search code examples
c++stringsubstringsubstr

c++ string member function substr usage


Please tell me if I am understanding the the substr member function correctly?
result = result.substr(0, pos) + result.substr(pos + 1);
It takes the string from pos, 0 until (but not including), remove[i]
and then + result.substr(pos + 1); concatenates the rest of the string, except but not including the string / char in remove?

string removeLetters2(string text, string remove)
{
    int pos;
    string result = text;

    for (int i = 0; i < remove.length(); i++)
    {
        while (true)
        {
            pos = result.find(remove[i]);                
            if (pos == string::npos)                      
            {
                break;
            }
            else
            {
                result = result.substr(0, pos) +
                result.substr(pos + 1);
            }
        }
    }
    return result;
}

Solution

  • In short, you are asking if

    result = result.substr(0, pos) +
             result.substr(pos + 1);
    

    removes the character at position pos, right?

    Short Answer:

    Yes.

    Longer Answer:

    The two-argument call takes the start index and the length (the one argument call goes to the end of string).

    It helps to imagine the string like this:

    F o o / B a r
    0 1 2 3 4 5 6   <- indices
    

    Now remove /:

    F o o / B a r
    0 1 2 3 4 5 6   <- indices
    1 2 3 |         <- 1st length
          | 1 2 3   <- 2nd length
    
    result = result.substr(0, 3)   <- from index 0 with length 3
           + result.substr(4);     <- from index 4 to end
    

    As a programmer, always be aware of the difference between distance/index and length.

    Better: If index is known:

    Your code creates two new, temporary strings, which are then concatenated into a third temporary string, which is then copied to result.

    It would be better to ask string to erase (wink wink) in place:

    result.erase(pos,1);
    // or by iterator
    string::iterator it = ....;
    result.erase(it,it+1);
    

    This leaves more optimization freedom to the string implementer, who may choose to just move all characters after pos by one to the left. This could, in a specialized scenario, be implemented with a single assignment, a single loop, and within the loop with the x86 swap instruction.

    Better: If characters to be deleted are known:

    Or, but I am not sure if this gives better performance, but it may give better code, the algorithm remove_if:

    #include <algorithm>
    
    // this would remove all slashes, question marks and dots
    ....
        std::string foobar = "ab/d?...";
        std::remove_if (foobar.begin(), foobar.end(), [](char c) {
            return c=='/' || c=='?' || '.';
        });
    

    remove_if accepts any function object.

    If there is just one character, it gets easier:

    // this would remove all slashes
    std::remove (foobar.begin(), foobar.end(), '/');