How to find and replace string?

If s is a std::string, then is there a function like the following?

s.replace("text to replace", "new text");

Solution 1:

Replace first match

Use a combination of std::string::find and std::string::replace.

Find the first match:

std::string s;
std::string toReplace("text to replace");
size_t pos = s.find(toReplace);

Replace the first match:

s.replace(pos, toReplace.length(), "new text");

A simple function for your convenience:

void replace_first(
    std::string& s,
    std::string const& toReplace,
    std::string const& replaceWith
) {
    std::size_t pos = s.find(toReplace);
    if (pos == std::string::npos) return;
    s.replace(pos, toReplace.length(), replaceWith);
}

Usage:

replace_first(s, "text to replace", "new text");

Demo.


Replace all matches

Define this O(n) method using std::ostringstream as a buffer:

void replace_all(
    std::string& s,
    std::string const& toReplace,
    std::string const& replaceWith
) {
    std::ostringstream oss;
    std::size_t pos = 0;
    std::size_t prevPos = pos;

    while (true) {
        prevPos = pos;
        pos = s.find(toReplace, pos);
        if (pos == std::string::npos)
            break;
        oss << s.substr(prevPos, pos - prevPos);
        oss << replaceWith;
        pos += toReplace.size();
    }

    oss << s.substr(prevPos);
    s = oss.str();
}

Usage:

replace_all(s, "text to replace", "new text");

Demo.


Boost

Alternatively, use boost::algorithm::replace_all:

#include <boost/algorithm/string.hpp>
using boost::replace_all;

Usage:

replace_all(s, "text to replace", "new text");

Solution 2:

Do we really need a Boost library for seemingly such a simple task?

To replace all occurences of a substring use this function:

std::string ReplaceString(std::string subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while ((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
    return subject;
}

If you need performance, here is an optimized function that modifies the input string, it does not create a copy of the string:

void ReplaceStringInPlace(std::string& subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while ((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
}

Tests:

std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;

std::cout << "ReplaceString() return value: " 
          << ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: " 
          << input << std::endl;

ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: " 
          << input << std::endl;

Output:

Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def