Replace part of a string with another string

C++StringReplaceSubstringStd

C++ Problem Overview


Is it possible in C++ to replace part of a string with another string?

Basically, I would like to do this:

QString string("hello $name");
string.replace("$name", "Somename");

But I would like to use the Standard C++ libraries.

C++ Solutions


Solution 1 - C++

There's a function to find a substring within a string (find), and a function to replace a particular range in a string with another string (replace), so you can combine those to get the effect you want:

bool replace(std::string& str, const std::string& from, const std::string& to) {
    size_t start_pos = str.find(from);
    if(start_pos == std::string::npos)
        return false;
    str.replace(start_pos, from.length(), to);
    return true;
}

std::string string("hello $name");
replace(string, "$name", "Somename");

In response to a comment, I think replaceAll would probably look something like this:

void replaceAll(std::string& str, const std::string& from, const std::string& to) {
    if(from.empty())
        return;
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
    }
}

Solution 2 - C++

With C++11 you can use std::regex like so:

#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");

The double backslash is required for escaping an escape character.

Solution 3 - C++

std::string has a replace method, is that what you are looking for?

You could try:

s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");

I haven't tried myself, just read the documentation on find() and replace().

Solution 4 - C++

To have the new string returned use this:

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

Solution 5 - C++

This sounds like an option

string.replace(string.find("%s"), string("%s").size(), "Something");

You could wrap this in a function but this one-line solution sounds acceptable. The problem is that this will change the first occurence only, you might want to loop over it, but it also allows you to insert several variables into this string with the same token (%s)

Solution 6 - C++

Yes, you can do it, but you have to find the position of the first string with string's find() member, and then replace with it's replace() member.

string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
   s.replace( pos, 5, "somename" );   // 5 = length( $name )
}

If you are planning on using the Standard Library, you should really get hold of a copy of the book The C++ Standard Library which covers all this stuff very well.

Solution 7 - C++

I use generally this:

std::string& replace(std::string& s, const std::string& from, const std::string& to)
{
	if(!from.empty())
		for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size())
			s.replace(pos, from.size(), to);
    return s;
}

It repeatedly calls std::string::find() to locate other occurrences of the searched for string until std::string::find() doesn't find anything. Because std::string::find() returns the position of the match we don't have the problem of invalidating iterators.

Solution 8 - C++

If all strings are std::string, you'll find strange problems with the cutoff of characters if using sizeof() because it's meant for C strings, not C++ strings. The fix is to use the .size() class method of std::string.

sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);

That replaces sHaystack inline -- no need to do an = assignment back on that.

Example usage:

std::string sHaystack = "This is %XXX% test.";
std::string sNeedle = "%XXX%";
std::string sReplace = "my special";
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
std::cout << sHaystack << std::endl;

Solution 9 - C++

wstring myString = L"Hello $$ this is an example. By $$.";
wstring search = L"$$";
wstring replace = L"Tom";
for (int i = myString.find(search); i >= 0; i = myString.find(search))
	myString.replace(i, search.size(), replace);

Solution 10 - C++

This could be even better to use

void replace(string& input, const string& from, const string& to)
{
    auto pos = 0;
    while(true)
    {
        size_t startPosition = input.find(from, pos);
        if(startPosition == string::npos)
            return;
        input.replace(startPosition, from.length(), to);
        pos += to.length();
    }
}

Solution 11 - C++

If you want to do it quickly you can use a two scan approach. Pseudo code:

  1. first parse. find how many matching chars.
  2. expand the length of the string.
  3. second parse. Start from the end of the string when we get a match we replace, else we just copy the chars from the first string.

I am not sure if this can be optimized to an in-place algo.

And a C++11 code example but I only search for one char.

#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
    
void ReplaceString(string& subject, char search, const string& replace)
{	
	size_t initSize = subject.size();
	int count = 0;
	for (auto c : subject) { 
		if (c == search) ++count;
	}

	size_t idx = subject.size()-1 + count * replace.size()-1;
	subject.resize(idx + 1, '\0');
	
	string reverseReplace{ replace };
	reverse(reverseReplace.begin(), reverseReplace.end());	
	
	char *end_ptr = &subject[initSize - 1];
	while (end_ptr >= &subject[0])
	{
		if (*end_ptr == search) {
			for (auto c : reverseReplace) {
				subject[idx - 1] = c;
				--idx;				
			}			
		}
		else {
			subject[idx - 1] = *end_ptr;
			--idx;
		}
		--end_ptr;
	}
}

int main()
{
	string s{ "Mr John Smith" };
	ReplaceString(s, ' ', "%20");
	cout << s << "\n";

}

Solution 12 - C++

std::string replace(std::string base, const std::string from, const std::string to) {
    std::string SecureCopy = base;

    for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos))
    {
        SecureCopy.replace(start_pos, from.length(), to);
    }

    return SecureCopy;
}

Solution 13 - C++

My own implementation, taking into account that string needs to be resized only once, then replace can happen.

template <typename T>
std::basic_string<T> replaceAll(const std::basic_string<T>& s, const T* from, const T* to)
{
    auto length = std::char_traits<T>::length;
    size_t toLen = length(to), fromLen = length(from), delta = toLen - fromLen;
    bool pass = false;
    std::string ns = s;

    size_t newLen = ns.length();

    for (bool estimate : { true, false })
    {
        size_t pos = 0;

        for (; (pos = ns.find(from, pos)) != std::string::npos; pos++)
        {
            if (estimate)
            {
                newLen += delta;
                pos += fromLen;
            }
            else
            {
                ns.replace(pos, fromLen, to);
                pos += delta;
            }
        }

        if (estimate)
            ns.resize(newLen);
    }

    return ns;
}

Usage could be for example like this:

std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");

Solution 14 - C++

I'm just now learning C++, but editing some of the code previously posted, I'd probably use something like this. This gives you the flexibility to replace 1 or multiple instances, and also lets you specify the start point.

using namespace std;

// returns number of replacements made in string
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) {
	if (from.empty()) return 0;

	size_t startpos = str.find(from, start);
	long replaceCount = 0;

	while (startpos != string::npos){
		str.replace(startpos, from.length(), to);
		startpos += to.length();
		replaceCount++;

		if (count > 0 && replaceCount >= count) break;
		startpos = str.find(from, startpos);
	}

	return replaceCount;
}

Solution 15 - C++

You can use this code for remove subtring and also replace , and also remove extra white space . code :

#include<bits/stdc++.h>
using namespace std ;
void removeSpaces(string &str)
{
   
    int n = str.length();

    int i = 0, j = -1;

    bool spaceFound = false;

    while (++j <= n && str[j] == ' ');

    while (j <= n)
    {
        if (str[j] != ' ')
        {
          
            if ((str[j] == '.' || str[j] == ',' ||
                 str[j] == '?') && i - 1 >= 0 &&
                 str[i - 1] == ' ')
                str[i - 1] = str[j++];

            else
                
                str[i++] = str[j++];

            
            spaceFound = false;
        }
        else if (str[j++] == ' ')
        {
            
            if (!spaceFound)
            {
                str[i++] = ' ';
                spaceFound = true;
            }
        }
    }

    if (i <= 1)
        str.erase(str.begin() + i, str.end());
    else
        str.erase(str.begin() + i - 1, str.end());
}
int main()
{
    string s;
    cin>>s;
    for(int i=s.find("WUB");i>=0;i=s.find("WUB"))
    {
        s.replace(i,3," ");
    }
    removeSpaces(s);
    cout<<s<<endl;

    return 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTom LeeseView Question on Stackoverflow
Solution 1 - C++Michael MrozekView Answer on Stackoverflow
Solution 2 - C++TomView Answer on Stackoverflow
Solution 3 - C++S.C. MadsenView Answer on Stackoverflow
Solution 4 - C++Czarek TomczakView Answer on Stackoverflow
Solution 5 - C++maxoumimeView Answer on Stackoverflow
Solution 6 - C++anonView Answer on Stackoverflow
Solution 7 - C++GalikView Answer on Stackoverflow
Solution 8 - C++VolomikeView Answer on Stackoverflow
Solution 9 - C++user3016543View Answer on Stackoverflow
Solution 10 - C++Yashwanth KumarView Answer on Stackoverflow
Solution 11 - C++DamianView Answer on Stackoverflow
Solution 12 - C++Lucas CivaliView Answer on Stackoverflow
Solution 13 - C++TarmoPikaroView Answer on Stackoverflow
Solution 14 - C++someprogrammerView Answer on Stackoverflow
Solution 15 - C++mubasshir00View Answer on Stackoverflow