//: C03:StringReplace.cpp
// Simple find-and-replace in strings
#include <cassert>
#include <string>
using namespace std;
int main() {
string s("A piece of text");
string tag("$tag$");
s.insert(8, tag + ' ');
assert(s == "A piece $tag$ of text");
int start = s.find(tag);
assert(start == 8);
assert(tag.size() == 5);
s.replace(start, tag.size(), "hello there");
assert(s == "A piece hello there of text");
} ///:~
The tag is first inserted into s (notice that the insert happens before the value indicating the insert point and that an extra space was added after tag), and then it is found and replaced.
You should actually check to see if you’ve found anything before you perform a replace( ). The previous example replaces with a char*, but there’s an overloaded version that replaces with a string. Here’s a more complete demonstration replace( ):
//: C03:Replace.cpp
#include <cassert>
#include <cstddef> // for size_t
#include <string>
using namespace std;
void replaceChars(string& modifyMe,
const string& findMe, const string& newChars) {
// Look in modifyMe for the "find string"
// starting at position 0
size_t i = modifyMe.find(findMe, 0);
// Did we find the string to replace?
if (i != string::npos)
// Replace the find string with newChars
modifyMe.replace(i, findMe.size(), newChars);
}
int main() {
string bigNews =
"I thought I saw Elvis in a UFO. "
"I have been working too hard.";
string replacement("wig");
string findMe("UFO");
// Find "UFO" in bigNews and overwrite it:
replaceChars(bigNews, findMe, replacement);
assert(bigNews == "I thought I saw Elvis in a "
"wig. I have been working too hard.");
} ///:~
If replace doesn’t find the search string, it returns string::npos. The npos data member is a static constant member of the string class that represents a nonexistent character position.[30]
Unlike insert( ), replace( ) won’t grow the string’s storage space if you copy new characters into the middle of an existing series of array elements. However, it will grow the storage space if needed, for example, when you make a "replacement" that would expand the original string beyond the end of the current allocation. Here’s an example:.
//: C03:ReplaceAndGrow.cpp
#include <cassert>
#include <string>
using namespace std;
int main() {
string bigNews("I have been working the grave.");
string replacement("yard shift.");
// The first arg says "replace chars
// beyond the end of the existing string":
bigNews.replace(bigNews.size() - 1,
replacement.size(), replacement);
assert(bigNews == "I have been working the "
"graveyard shift.");
} ///:~
The call to replace( ) begins "replacing" beyond the end of the existing array, which is equivalent to an append operation. Notice that in this example replace( ) expands the array accordingly.
You may have been hunting through this chapter trying to do something relatively simple such as replace all the instances of one character with a different character. Upon finding the previous material on replacing, you thought you found the answer, but then you started seeing groups of characters and counts and other things that looked a bit too complex. Doesn’t string have a way to just replace one character with another everywhere?.
You can easily write such a function using the find( ) and replace( ) member functions as follows:
//: C03:ReplaceAll.cpp {O}
#include <cstddef>
#include <string>
using namespace std;
string& replaceAll(string& context, const string& from,
const string& to) {
size_t lookHere = 0;
size_t foundHere;
while ((foundHere = context.find(from, lookHere))
!= string::npos) {
context.replace(foundHere, from.size(), to);
lookHere = foundHere + to.size();
}
return context;
} ///:~
The version of find( ) used here takes as a second argument the position to start looking in and returns string::npos if it doesn’t find it. It is important to advance the position held in the variable lookHere past the replacement string, of course, in case from is a substring of to. The following program tests the replaceAll function:.
//: C03:ReplaceAllTest.cpp
//{-msc}
//{L} ReplaceAll
#include <iostream>
#include <cassert>
using namespace std;
string& replaceAll(string& context, const string& from,
const string& to);
int main() {
string text = "a man, a plan, a canal, panama";
replaceAll(text, "an", "XXX");
assert(text == "a mXXX, a plXXX, a cXXXal, pXXXama");
} ///:~
As you can see, the string class by itself doesn’t solve all possible problems. Many solutions have been left to the algorithms in the Standard library,[31] because the string class can look just like an STL sequence (by virtue of the iterators discussed earlier). All the generic algorithms work on a "range" of elements within a container. Usually that range is just "from the beginning of the container to the end." A string object looks like a container of characters: to get the beginning of the range you use string::begin( ), and to get the end of the range you use string::end( ). The following example shows the use of the replace( ) algorithm to replace all the instances of the single character ‘X’ with ‘Y’:.
//: C03:StringCharReplace.cpp
#include <algorithm>
#include <cassert>
#include <string>
using namespace std;
int main() {
string s("aaaXaaaXXaaXXXaXXXXaaa");
replace(s.begin(), s.end(), 'X', 'Y');