How do I Search/Find and Replace in a standard string?

Viewed 124075

How do I replace all occurrences of a substring with another string, for std::strings?

std::string s ("One hello, two hellos.");
s = s.replace("hello", "world");  // something like this
10 Answers

Performant O(n) replace all

Many other answers repeatedly call std::string::replace, which requires the string to be overwritten repeatedly, which results in poor performance. In contrast, this uses a std::string buffer so that each character of the string is only traversed once:

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

    // Reserves rough estimate of final size of string.
    buf.reserve(s.size());

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

    buf.append(s, prevPos, s.size() - prevPos);
    s.swap(buf);
}

Usage:

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

Full example:
#include <iostream>
#include <sstream>

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

    // Reserves rough estimate of final size of string.
    buf.reserve(s.size());

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

    buf.append(s, prevPos, s.size() - prevPos);
    s.swap(buf);
}

int main() {
    std::string s("hello hello, mademoiselle!");
    replace_all(s, "hello", "bye");
    std::cout << s << std::endl;
}

Output:

bye bye, mademoiselle!

Note: Previous versions of this answer used std::ostringstream, which has some overhead. The latest version uses std::string::append instead, as recommended by @LouisGo.

// Replace all occurrences of searchStr in str with replacer
// Each match is replaced only once to prevent an infinite loop
// The algorithm iterates once over the input and only concatenates 
// to the output, so it should be reasonably efficient
std::string replace(const std::string& str, const std::string& searchStr, 
    const std::string& replacer)
{
    // Prevent an infinite loop if the input is empty
    if (searchStr == "") {
        return str;
    }

    std::string result = "";
    size_t pos = 0;
    size_t pos2 = str.find(searchStr, pos);

    while (pos2 != std::string::npos) {
        result += str.substr(pos, pos2-pos) + replacer;
        pos = pos2 + searchStr.length();
        pos2 = str.find(searchStr, pos);
    }

    result += str.substr(pos, str.length()-pos);
    return result;
}
Related