71

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

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

11 Answers 11

105

Replace first match

Use std::string::find to find the first occurrence of the string toReplace.
Use std::string::replace to replace that occurrence with the string replaceWith.

This function does that:

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::string as a buffer:

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");

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");
4
  • 2
    if "text to replace" is longer or shorter than the length of the "new text", what will the string::replace do? memmove the string to fill the gap?
    – Alcott
    Commented Sep 16, 2011 at 2:25
  • @Alcott It'll allocate memory for a "new" string of the correct size, fill in the data, and delete the "old" string. Commented Sep 16, 2011 at 2:45
  • I think it is a bit confusing to accept a string as reference and return it: It is not clear without reading the code what is the returned string or if I need to save it. I would just return void or accept const std::string& s, but not both. Commented Jun 3, 2021 at 6:58
  • @AdrianMaire I was trying to match the signature of std::string::replace, but I agree that it's a bit confusing, so I've changed it for now. Commented Jan 4, 2022 at 12:12
35

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
3
  • 11
    I say: yes, because it replaces your own code with peer-reviewed code. The same reason you're using std::string and std::cout. Now, if you're trying to reduce dependencies, that's another question.
    – strickli
    Commented Aug 19, 2013 at 19:57
  • 2
    The issue with replace() being called many times is that each time it might be moving the right hand part of the string (assuming the "replace" is not the same length as the "find". Therefore if memory is not an issue I'd prefer to write everything to a new string.
    – CashCow
    Commented Jan 7, 2015 at 15:54
  • 1
    calling this with an empty search string results in an infinite loop. perhaps return subject if search.empty() is true. (drawback: this makes it so you can't search for an empty string and replace it with a non-empty string). Commented Aug 26, 2018 at 7:35
25

Yes: replace_all is one of the boost string algorithms:

Although it's not a standard library, it has a few things on the standard library:

  1. More natural notation based on ranges rather than iterator pairs. This is nice because you can nest string manipulations (e.g., replace_all nested inside a trim). That's a bit more involved for the standard library functions.
  2. Completeness. This isn't hard to be 'better' at; the standard library is fairly spartan. For example, the boost string algorithms give you explicit control over how string manipulations are performed (i.e., in place or through a copy).
1
  • 1
    +1: this boost library seems little known, yet it's perhaps the one I use the most. Commented May 4, 2011 at 6:24
19
#include <iostream>
#include <string>
using namespace std;

int main ()
{
    string str("one three two four");
    string str2("three");
    str.replace(str.find(str2),str2.length(),"five");
    cout << str << endl;
    return 0;
}

Output

one five two four
2
  • This might crash if the string is not found
    – yoel halb
    Commented Nov 3, 2023 at 1:27
  • @yoelhalb With fixed data, it's never going to crash. This is just an example with no error checking. Commented Nov 3, 2023 at 2:27
7

like some say boost::replace_all

here a dummy example:

    #include <boost/algorithm/string/replace.hpp>

    std::string path("file.gz");
    boost::replace_all(path, ".gz", ".zip");
0
3

Not exactly that, but std::string has many replace overloaded functions.

Go through this link to see explanation of each, with examples as to how they're used.

Also, there are several versions of string::find functions (listed below) which you can use in conjunction with string::replace.

  • find
  • rfind
  • find_first_of
  • find_last_of
  • find_first_not_of
  • find_last_not_of

Also, note that there are several versions of replace functions available from <algorithm> which you can also use (instead of string::replace):

  • replace
  • replace_if
  • replace_copy
  • replace_copy_if
2
  • 2
    This does not answer the question.
    – Tom Swirly
    Commented Mar 2, 2014 at 21:16
  • find or rfind are the only appropriate ones. std::replace works for string only if it is char-to-char replace i.e. replacing all the spaces with underscores or whatever.
    – CashCow
    Commented Jan 7, 2015 at 15:56
2
// replaced text will be in buffer.
void Replace(char* buffer, const char* source, const char* oldStr,  const char* newStr)
{
    if(buffer==NULL || source == NULL || oldStr == NULL || newStr == NULL) return; 

    int slen = strlen(source);
    int olen = strlen(oldStr);
    int nlen = strlen(newStr);

    if(olen>slen) return;
    int ix=0;

    for(int i=0;i<slen;i++)
    {
        if(oldStr[0] == source[i])
        {
            bool found = true;
            for(int j=1;j<olen;j++)
            {
                if(source[i+j]!=oldStr[j])
                {
                    found = false;
                    break;
                }
            }

            if(found)
            {
                for(int j=0;j<nlen;j++)
                    buffer[ix++] = newStr[j];

                i+=(olen-1);
            }
            else
            {
                buffer[ix++] = source[i];
            }
        }
        else
        {
            buffer[ix++] = source[i];
        }
    }
}
1
  • Nice function, but doesn't handle squeezing space characters very well. For example, replace two spaces with one space would have to be run multiple times to get just one space between characters in some cases.
    – swdev
    Commented Apr 25, 2014 at 7:42
1

is there a function like the following?

One other(in addition to using boost and other methods given in different answers) possible way of doing this is using std::regex_replace as shown below:

    std::string s{"my name is my name and not my name mysometext myto"}; //this is the original line
    
    std::string replaceThis = "my";
    std::string replaceWith = "your";
    
    std::regex pattern("\\b" + replaceThis + "\\b");
    
    std::string replacedLine = std::regex_replace(s, pattern, replaceWith);

    std::cout<<replacedLine<<std::endl;
0

Here's the version I ended up writing that replaces all instances of the target string in a given string. Works on any string type.

template <typename T, typename U>
T &replace (
          T &str, 
    const U &from, 
    const U &to)
{
    size_t pos;
    size_t offset = 0;
    const size_t increment = to.size();

    while ((pos = str.find(from, offset)) != T::npos)
    {
        str.replace(pos, from.size(), to);
        offset = pos + increment;
    }

    return str;
}

Example:

auto foo = "this is a test"s;
replace(foo, "is"s, "wis"s);
cout << foo;

Output:

thwis wis a test

Note that even if the search string appears in the replacement string, this works correctly.

0
void replace(char *str, char *strFnd, char *strRep)
{
    for (int i = 0; i < strlen(str); i++)
    {
        int npos = -1, j, k;
        if (str[i] == strFnd[0])
        {
            for (j = 1, k = i+1; j < strlen(strFnd); j++)
                if (str[k++] != strFnd[j])
                    break;
            npos = i;
        }
        if (npos != -1)
            for (j = 0, k = npos; j < strlen(strRep); j++)
                str[k++] = strRep[j];
    }

}

int main()
{
    char pst1[] = "There is a wrong message";
    char pfnd[] = "wrong";
    char prep[] = "right";

    cout << "\nintial:" << pst1;

    replace(pst1, pfnd, prep);

    cout << "\nfinal : " << pst1;
    return 0;
}
0
void replaceAll(std::string & data, const std::string &toSearch, const std::string &replaceStr)
{
    // Get the first occurrence
    size_t pos = data.find(toSearch);
    // Repeat till end is reached
    while( pos != std::string::npos)
    {
        // Replace this occurrence of Sub String
        data.replace(pos, toSearch.size(), replaceStr);
        // Get the next occurrence from the current position
        pos =data.find(toSearch, pos + replaceStr.size());
    }
}

More CPP utilities: https://github.com/Heyshubham/CPP-Utitlities/blob/master/src/MEString.cpp#L60

Not the answer you're looking for? Browse other questions tagged or ask your own question.