Joining a Sequence of Strings

Problem

Given a sequence of strings, such as output from Example 4-10, you want to join them together into a single, long string, perhaps with a delimiter.

Solution

Loop through the sequence and append each string to the output string. You can handle any standard sequence as input; Example 4-13 uses a vector of strings.

Example 4-13. Join a sequence of strings

#include 
#include 
#include 

using namespace std;

void join(const vector& v, char c, string& s) {

 s.clear( );

 for (vector::const_iterator p = v.begin( );
 p != v.end( ); ++p) {
 s += *p;
 if (p != v.end( ) - 1)
 s += c;
 }
}

int main( ) {

 vector v;
 vector v2;
 string s;

 v.push_back(string("fee"));
 v.push_back(string("fi"));
 v.push_back(string("foe"));
 v.push_back(string("fum"));

 join(v, '/', s);

 cout << s << '
';
}

 

Discussion

Example 4-13 has one technique that is slightly different from previous examples. Look at this line:

for (vector::const_iterator p = v.begin( );

The previous string examples simply used iterators, without the "const" part, but you can't get away with that here because v is declared as a reference to a const object. If you have a const container object, you can only use a const_iterator to access its elements. This is because a plain iterator allows writes to the object it refers to, which, of course, you can't do if your container object is const.

I declared v const for two reasons. First, I know I'm not going to be modifying its contents, so I want the compiler to give me an error if I do. The compiler is much better at spotting that kind of thing than I am, especially since a subtle syntactic or semantic error can cause an unwanted assignment. Second, I want to advertise to consumers of this function that I won't do anything to their container, and const is the perfect way to do that. Now, I just have to create a generic version that works on multiple character types.

Just as in Recipe 4.6, making join generic with a function template is easy. All you have to do is change the header to be parameterized on the type of character, like this:

template
void joing(const std::vector >& v, T c,
 std::basic_string& s)

But vectors may not be your only input. You may be saddled with the task of joining an array of C-style strings. C++ strings are preferable to C-style strings, so if you have to do this, join them into a C++ string. Once you've done that, you can always retrieve a C-style version by calling string's c_str member function, which returns a const pointer to a null-terminated character array.

Example 4-14 offers a generic version of join that joins an array of character arrays into a string. Since the new, generic version is parameterized on the character type, it will work for narrow or wide character arrays.

Example 4-14. Joining C-style strings

#include 
#include 

const static int MAGIC_NUMBER = 4;

template
void join(T* arr[], size_t n, T c, std::basic_string& s) {
 s.clear( );

 for (int i = 0; i < n; ++i) {
 if (arr[i] != NULL)
 s += arr[i];
 if (i < n-1)
 s += c;
 }
}

int main( ) {
 std::wstring ws;

 wchar_t* arr[MAGIC_NUMBER];

 arr[0] = L"you";
 arr[1] = L"ate";
 arr[2] = L"my";
 arr[3] = L"breakfast";

 join(arr, MAGIC_NUMBER, L'/', ws);


}






C++ Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2006
Pages: 241
Simiral book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net