| Message
| Strings
STL includes a nice "string" class that lets you do all sorts of things with strings. However one thing it doesn't have built-in is find-and-replace. However it is easy to write your own. Here is an example ...
Example 5
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
using namespace std;
// string find-and-replace
string FindAndReplace
(const string& source, const string target, const string replacement)
{
string str = source;
string::size_type pos = 0, // where we are now
found; // where the found data is
if (target.size () > 0) // searching for nothing will cause a loop
{
while ((found = str.find (target, pos)) != string::npos)
{
str.replace (found, target.size (), replacement);
pos = found + replacement.size ();
}
}
return str;
}; // end of FindAndReplace
int main (void)
{
string s;
s = "Nick Gammon is working today and not working tomorrow";
cout << FindAndReplace (s, "working", "sleeping") << endl;
return 0;
} // end of main
Output
Nick Gammon is sleeping today and not sleeping tomorrow
Getting a bit fancier now, we'll try making a deck of cards and shuffling it...
Example 6
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <time.h>
using namespace std;
#define NUMITEMS(x) (sizeof(x) / sizeof(x[0]))
#define MAKE_STRING(msg) \
(((ostringstream&) (ostringstream() << msg)).str())
// used for generate_n: adds 1 to a starting number
// and returns a string with that number
class AddN : public unary_function<int, string>
{
int start;
public:
AddN (const int n) : start (n) {}; // constructor, initialises sequence
string operator() () { return MAKE_STRING (start++); };
};
int main (void)
{
// my vector of cards
vector<string> cards;
// honour cards have special names - use a C array
string honours [] = { "Ace", "King", "Queen", "Jack" };
// copy from C array to vector - back_insert adds to vector cards
copy (honours, &honours [ NUMITEMS (honours) ], back_inserter (cards));
// generate 9 other cards starting at 2
generate_n (back_inserter (cards), 9, AddN (2));
// add the word " hearts" to the end of each one
transform (cards.begin (), cards.end (),
cards.begin (),
bind2nd (plus<string> (), " hearts"));
// shuffle them
srand(time(NULL));
// srand48(time(NULL)); // use on Linux
random_shuffle (cards.begin (), cards.end ());
// display them
copy (cards.begin (), cards.end (),
ostream_iterator<string> (cout, ", "));
cout << endl;
return 0;
} // end of main
Output
9 hearts, 5 hearts, 3 hearts, 4 hearts, Queen hearts, Jack hearts, 7 hearts, 6 hearts, Ace hearts, King hearts, 10 hearts, 8 hearts, 2 hearts,
This example illustrates a few more things - using generate_n to generate a sequence (adding 1 each time) - this is similar in concept to the increment_fill in the earlier example (example 4) but showing how we can do the same thing by writing a function that is called by the generate_n algorithm.
In this case I wanted the numbers to be strings (so we could put names like hearts, clubs, etc. after them) so a slightly different approach was warranted.
The MAKE_STRING define I found on another website, it lets you transform arbitrary mixtures of numbers and text into a single string.
For example:
string mystr = MAKE_STRING (
"hello " << boolalpha << true <<
hex << 1234 <<
octal << 3456 <<
dec << 123456 <<
scientific << 123.45 <<
fixed << 1234.567 " );
The keywords "hex" "octal" etc. let you change the base for numbers.
The other really interesting thing in this example is the use of "transform" with "plus" to add the word "hearts" to the end of each item in the vector.
What is happening is that transform applies a transformation to each item in a sequence, in this case the transformation is plus<string> (ie. string concatenation) and the second argument is "hearts". To bind the argument "hearts" to the "plus" we use bind2nd.
To get a bit fancier again, we'll make a copy of the 13 cards and then change "hearts" to "diamonds". To do this we need to use the "insert" member function of vector, and then write a specialised Find_Replace unary function which can be called by transform. However to avoid hard-coding what we are finding and replacing, we will make a special unary function "Find_Replace". When it is instantiated its constructor is passed what to find, and what to replace it with. It saves those in internal variables.
Then the transform function calls the operator() once for each element in the array, effectively doing the find/replace for us on each element. Changes in bold.
Example 7
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <time.h>
using namespace std;
#define NUMITEMS(x) (sizeof(x) / sizeof(x[0]))
#define MAKE_STRING(msg) \
(((ostringstream&) (ostringstream() << msg)).str())
// used for generate_n: adds 1 to a starting number
// and returns a string with that number
class AddN : public unary_function<int, string>
{
int start;
public:
AddN (const int n) : start (n) {}; // constructor, initialises sequence
string operator() () { return MAKE_STRING (start++); };
};
// string find-and-replace
inline string FindAndReplace
(const string& source, const string target, const string replacement)
{
string str = source;
string::size_type pos = 0, // where we are now
found; // where the found data is
if (target.size () > 0) // searching for nothing will cause a loop
{
while ((found = str.find (target, pos)) != string::npos)
{
str.replace (found, target.size (), replacement);
pos = found + replacement.size ();
}
}
return str;
}; // end of FindAndReplace
// a functor that will find and replace
class Find_Replace : public unary_function<string, string>
{
const string target;
const string replacement;
public:
Find_Replace (const string tar, const string repl)
: target (tar), replacement (repl) {}; // constructor
string operator() (const string & str)
{ return FindAndReplace (str, target, replacement); };
};
int main (void)
{
// my vector of cards
vector<string> cards;
// honour cards have special names - use a C array
string honours [] = { "Ace", "King", "Queen", "Jack" };
// copy from C array to vector - back_insert adds to vector cards
copy (honours, &honours [ NUMITEMS (honours) ], back_inserter (cards));
// generate 9 other cards starting at 2
generate_n (back_inserter (cards), 9, AddN (2));
// add the word " hearts" to the end of each one
transform (cards.begin (), cards.end (),
cards.begin (),
bind2nd (plus<string> (), " hearts"));
// make a copy at the end
cards.insert (cards.end (), cards.begin (), cards.end ());
// convert the word "hearts" to "diamonds"
transform (cards.begin (), cards.begin () + 13,
cards.begin (),
Find_Replace ("hearts", "diamonds"));
// shuffle them
srand(time(NULL));
// srand48(time(NULL)); // use on Linux
random_shuffle (cards.begin (), cards.end ());
// display them
copy (cards.begin (), cards.end (),
ostream_iterator<string> (cout, ", "));
cout << endl;
return 0;
} // end of main
Output
10 hearts, 9 diamonds, Queen diamonds, 6 hearts, 3 diamonds, 2 diamonds, 4 hearts, 2 hearts, Jack diamonds, Ace hearts, 8 diamonds, King diamonds, Jack hearts, Ace diamonds, 10 diamonds, 8 hearts, King hearts, 5 hearts, 4 diamonds, 7 diamonds, 9 hearts, 3 hearts, 5 diamonds, Queen hearts, 7 hearts, 6 diamonds,
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|