68

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

s.replace("text to replace", "new text");
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
neuromancer
  • 53,769
  • 78
  • 166
  • 223
  • 2
    http://www.cplusplus.com/reference/string/string/replace/ – Lasse Espeholt May 04 '11 at 04:59
  • 8
    There is no such direct replace, but it should have been there. I was also searching for the same for a long time. – iammilind May 04 '11 at 05:08
  • 2
    possible duplicate of [How do I Search/Find and Replace in a standard string?](http://stackoverflow.com/questions/1494399/how-do-i-search-find-and-replace-in-a-standard-string) – Jet Jun 23 '15 at 19:57
  • Possible duplicate of [Replace part of a string with another string](https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string) – phuclv Aug 03 '18 at 05:16

11 Answers11

101

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");
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 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 Sep 16 '11 at 02:25
  • @Alcott It'll allocate memory for a "new" `string` of the correct size, fill in the data, and delete the "old" `string`. – Mateen Ulhaq Sep 16 '11 at 02: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. – Adrian Maire Jun 03 '21 at 06: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. – Mateen Ulhaq Jan 04 '22 at 12:12
34

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
Czarek Tomczak
  • 20,079
  • 5
  • 49
  • 56
  • 10
    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 Aug 19 '13 at 19:57
  • 1
    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 Jan 07 '15 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). – Matthew Piatt Aug 26 '18 at 07: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).
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
phooji
  • 10,086
  • 2
  • 38
  • 45
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
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
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");
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
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    This does not answer the question. – Tom Swirly Mar 02 '14 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 Jan 07 '15 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];
        }
    }
}
  • 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 Apr 25 '14 at 07:42
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.

anisoptera
  • 1,098
  • 7
  • 17
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;
}
snb
  • 633
  • 1
  • 6
  • 13
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

Shubham Agrawal
  • 559
  • 6
  • 15
0

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;
Jason
  • 36,170
  • 5
  • 26
  • 60