Tomasz Kasperczyk
Tomasz Kasperczyk

Reputation: 2093

Replace words in a string without skipping whitespaces

I've got a string which contains a sentence. I have to search and replace a specific word in that string. In my case I have a vector of lines and another vector of words to replace. Here's my function that generates a file with the final text:

void Generator::generate_file(const string& fileName){
    string inBuffer, outBuffer;
    std::stringstream ss;
    std::ofstream outFile;
    outFile.open(fileName);
    for (const auto& inIT : userCode){ 
        //userCode is a vector which contains lines of text
        ss.str(inIT);
        ss.clear();
        outBuffer = "";
        while (ss >> inBuffer){
            for (auto keyIT : keywords){
               //keywords is a vector which contains words to replace
                if (keyIT == inBuffer)
                    inBuffer = "REPLACED";
            }
            outBuffer += inBuffer + " ";
        }
        outFile << outBuffer << endl;
    }
    outFile.close();
}

The problem with this function is that it skips all whitespaces. I need them in the output file. What should I do to achieve that? Below you can see an example of how it works:

userCode:

userCode[0] = "class UrlEncoder(object): class";
userCode[1] = "    def __init__(self, alphabet=DEFAULT_ALPHABET,\n block_size=DEFAULT_BLOCK_SIZE):";

Displaying the userCode vector:

class UrlEncoder(object):
    def __init__(self, alphabet=DEFAULT_ALPHABET, block_size=DEFAULT_BLOCK_SIZE):

After executing my function it looks like this:

REPLACED UrlEncoder(object): 
REPLACED __init__(self, alphabet=DEFAULT_ALPHABET, block_size=DEFAULT_BLOCK_SIZE):

As you can see it properly replaced the keywords. But unfortunately it skipped the tabulator.

Upvotes: 1

Views: 84

Answers (1)

greatwolf
greatwolf

Reputation: 20858

The main issue is the way the stream extraction >> operator works. It removes and discards any leading whitespace characters when reading the next formatted input. Assuming you want to stick with using ss >> inBuffer when grabbing input, you need to find someway to preemptively grab any leading whitespace before you perform any input extraction.

For example,

string eatwhite(const string &str, size_t pos)
{
  size_t endwhite = str.find_first_not_of(" \t\n", pos);
  if (endwhite == string::npos) return "";
  return string(str.begin() + pos, str.begin() + endwhite);
}

Now you would call eatwhite before doing any >>:

    string outBuffer = eatwhite(ss.str(), ss.tellg());
    while (ss >> inBuffer)
    {
        for (auto keyIT : keywords)
        {
           //...
        }
        string whitesp = eatwhite(ss.str(), ss.tellg());
        outBuffer += inBuffer + whitesp;
    }
    outFile << outBuffer << endl;

Upvotes: 1

Related Questions