Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
The insert( ) function is particularly
nice because it absolves you from making sure the insertion of characters in a
string won t overrun the storage space or overwrite the characters immediately
following the insertion point. Space grows, and existing characters politely
move over to accommodate the new elements. Sometimes this might not be what you
want. If you want the size of the string to remain unchanged, use the replace( ) function to overwrite characters. There are a number of
overloaded versions of replace( ), but the simplest one takes three
arguments: an integer indicating where to start in the string, an integer
indicating how many characters to eliminate from the original string, and the
replacement string (which can be a different number of characters than the
eliminated quantity). Here s a simple example:
//: 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 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.
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 argument 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.h
#ifndef REPLACEALL_H
#define REPLACEALL_H
#include <string>
std::string& replaceAll(std::string& context,
const std::string& from, const std::string&
to);
#endif // REPLACEALL_H ///:~
//: C03:ReplaceAll.cpp {O}
#include <cstddef>
#include "ReplaceAll.h"
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, in case from is a
substring of to. The following program tests the replaceAll
function:
//: C03:ReplaceAllTest.cpp
//{L} ReplaceAll
#include <cassert>
#include <iostream>
#include <string>
#include "ReplaceAll.h"
using namespace std;
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 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');
assert(s == "aaaYaaaYYaaYYYaYYYYaaa");
} ///:~
Notice that this replace( ) is not called
as a member function of string. Also, unlike the string::replace( )
functions that only perform one replacement, the replace( )
algorithm replaces all instances of one character with another.
The replace( ) algorithm only works with single
objects (in this case, char objects) and will not replace quoted char
arrays or string objects. Since a string behaves like an STL
sequence, a number of other algorithms can be applied to it, which might solve
other problems that are not directly addressed by the string member
functions.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |