#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
using namespace std;
#define SPACES " \t\r\n"
inline string trim_right (const string & s, const string & t = SPACES)
{
string d (s);
string::size_type i (d.find_last_not_of (t));
if (i == string::npos)
return "";
else
return d.erase (d.find_last_not_of (t) + 1) ;
} // end of trim_right
inline string trim_left (const string & s, const string & t = SPACES)
{
string d (s);
return d.erase (0, s.find_first_not_of (t)) ;
} // end of trim_left
inline string trim (const string & s, const string & t = SPACES)
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim
// returns a lower case version of the string
string tolower (const string & s)
{
string d (s);
transform (d.begin (), d.end (), d.begin (), (int(*)(int)) tolower);
return d;
} // end of tolower
// returns an upper case version of the string
string toupper (const string & s)
{
string d (s);
transform (d.begin (), d.end (), d.begin (), (int(*)(int)) toupper);
return d;
} // end of toupper
// transformation function for tocapitals that has a "state"
// so it can capitalise a sequence
class fCapitals : public unary_function<char,char>
{
bool bUpper;
public:
// first letter in string will be in capitals
fCapitals () : bUpper (true) {}; // constructor
char operator() (const char & c)
{
char c1;
// capitalise depending on previous letter
if (bUpper)
c1 = toupper (c);
else
c1 = tolower (c);
// work out whether next letter should be capitals
bUpper = isalnum (c) == 0;
return c1;
}
}; // end of class fCapitals
// returns a capitalized version of the string
string tocapitals (const string & s)
{
string d (s);
transform (d.begin (), d.end (), d.begin (), fCapitals ());
return d;
} // end of tocapitals
// split a line into the first word, and rest-of-the-line
string GetWord (string & s,
const string delim = " ",
const bool trim_spaces = true)
{
// find delimiter
string::size_type i (s.find (delim));
// split into before and after delimiter
string w (s.substr (0, i));
// if no delimiter, remainder is empty
if (i == string::npos)
s.erase ();
else
// erase up to the delimiter
s.erase (0, i + delim.size ());
// trim spaces if required
if (trim_spaces)
{
w = trim (w);
s = trim (s);
}
// return first word in line
return w;
} // end of GetWord
// To be symmetric, we assume an empty string (after trimming spaces)
// will give an empty vector.
// However, a non-empty string (with no delimiter) will give one item
// After that, you get an item per delimiter, plus 1.
// eg. "" => empty
// "a" => 1 item
// "a,b" => 2 items
// "a,b," => 3 items (last one empty)
void StringToVector (const string s,
vector<string> & v,
const string delim = " ",
const bool trim_spaces = true)
{
// start with initial string, trimmed of leading/trailing spaces if required
string s1 (trim_spaces ? trim (s) : s);
v.clear (); // ensure vector empty
// no string? no elements
if (s1.empty ())
return;
// add to vector while we have a delimiter
while (!s1.empty () && s1.find (delim) != string::npos)
v.push_back (GetWord (s1, delim, trim_spaces));
// add final element
v.push_back (s1);
} // end of StringToVector
// Takes a vector of strings and converts it to a string
// like "apples,peaches,pears"
// Should be symmetric with StringToVector (excepting any spaces that might have
// been trimmed).
string VectorToString (const vector<string> & v,
const string delim = " ")
{
// vector empty gives empty string
if (v.empty ())
return "";
// for copying results into
ostringstream os;
// copy all but last one, with delimiter after each one
copy (v.begin (), v.end () - 1,
ostream_iterator<string> (os, delim.c_str ()));
// return string with final element appended
return os.str () + *(v.end () - 1);
} // end of VectorToString
int main (void)
{
string s (" happy/days/ are /here/again//// ");
vector<string> v;
StringToVector (s, v, "/");
// display item count
cout << "Converted string into " << v.size () << " items." << endl;
// convert back into string
cout << "Vector back to string = ("
<< VectorToString (v, ", ") << ")" << endl;
// test other routines
cout << "original -->" << s << "<--" << endl;
cout << "trim_right -->" << trim_right (s) << "<--" << endl;
cout << "trim_left -->" << trim_left (s) << "<--" << endl;
cout << "trim -->" << trim (s) << "<--" << endl;
cout << "tolower -->" << tolower (s) << "<--" << endl;
cout << "toupper -->" << toupper (s) << "<--" << endl;
cout << "tocapitals -->" << tocapitals (s) << "<--" << endl;
cout << "GetWord -->" << GetWord (s, "/") << "<--" << endl;
cout << "After GetWord, s = -->" << s << "<--" << endl;
return 0;
} // end of main
Output
Converted string into 9 items.
Vector back to string = (happy, days, are, here, again, , , , )
original --> happy/days/ are /here/again//// <--
trim_right --> happy/days/ are /here/again////<--
trim_left -->happy/days/ are /here/again//// <--
trim -->happy/days/ are /here/again////<--
tolower --> happy/days/ are /here/again//// <--
toupper --> HAPPY/DAYS/ ARE /HERE/AGAIN//// <--
tocapitals --> Happy/Days/ Are /Here/Again//// <--
GetWord -->happy<--
After GetWord, s = -->days/ are /here/again////<--
#include <string>
#include <iostream>
#include <functional>
using namespace std;
// case-independent (ci) string compare
// returns true if strings are EQUAL
struct ci_equal_to : binary_function <string, string, bool>
{
struct compare_equal
: public binary_function <unsigned char, unsigned char,bool>
{
bool operator() (const unsigned char& c1, const unsigned char& c2) const
{ return tolower (c1) == tolower (c2); }
}; // end of compare_equal
bool operator() (const string & s1, const string & s2) const
{
pair <string::const_iterator,
string::const_iterator> result =
mismatch (s1.begin (), s1.end (), // source range
s2.begin (), // comparison start
compare_equal ()); // comparison
// match if both at end
return result.first == s1.end () &&
result.second == s2.end ();
}
}; // end of ci_equal_to
// compare strings for equality using the binary function above
// returns true is s1 == s2
bool ciStringEqual (const string & s1, const string & s2)
{
return ci_equal_to () (s1, s2);
} // end of ciStringEqual
// case-independent (ci) string less_than
// returns true if s1 < s2
struct ci_less : binary_function <string, string, bool>
{
// case-independent (ci) compare_less binary function
struct compare_less
: public binary_function <unsigned char, unsigned char,bool>
{
bool operator() (const unsigned char& c1, const unsigned char& c2) const
{ return tolower (c1) < tolower (c2); }
}; // end of compare_less
bool operator() (const string & s1, const string & s2) const
{
return lexicographical_compare
(s1.begin (), s1.end (), // source range
s2.begin (), s2.end (), // dest range
compare_less ()); // comparison
}
}; // end of ci_less
// compare strings for less-than using the binary function above
// returns true if s1 < s2
bool ciStringLess (const string & s1, const string & s2)
{
return ci_less () (s1, s2);
} // end of ciStringLess
// compare to see if start of s1 is s2
// eg. returns true for: strPrefix ("abacus", "aba");
bool strPrefix (const string & s1, // string to search
const string & s2, // what to look for
const bool no_case = false) // case-insensitive?
{
// if either string is empty or s1 is smaller than s2
// then they can't be identical
if (s1.empty () ||
s2.empty () ||
s1.size () < s2.size ())
return false;
if (no_case)
return ciStringEqual (s1.substr (0, s2.size ()), s2);
else
return s1.substr (0, s2.size ()) == s2;
} // end of strPrefix
// compares to see if (s1, offset by pos, for length s2) == s2
bool strPrefix (const string & s1, // string to search
const string::size_type pos, // where in s1 to start
const string & s2, // what to look for
const bool no_case = false) // case-insensitive?
{
// can't be true if position outside string size
// casts are to ensure a signed comparison
if ((int) pos >= ((int) s1.size () - (int) s2.size ()))
return false;
// make a substring of s1 for s2's size
return strPrefix (s1.substr (pos, s2.size ()), s2, no_case);
} // end of strPrefix
// test
int main (void)
{
cout << boolalpha;
cout << "Should be true ..." << endl << endl;
// these should be true
cout << "Nick == nick = " << ciStringEqual ("Nick", "nick") << endl;
cout << "Nick >= nick = " << !ciStringLess ("Nick", "nick") << endl;
cout << "Nick prefix == Ni = " << strPrefix ("Nick", "Ni") << endl;
cout << "Nick ci_prefix == ni = " << strPrefix ("Nick", "ni", true) << endl;
cout << "AABBC prefix (2) == BB = " << strPrefix ("AABBC", 2, "BB") << endl;
cout << endl << "Should be false ..." << endl << endl;
// these should be false
cout << "Nick == nicky = " << ciStringEqual ("Nick", "nicky") << endl;
cout << "Nick < aaaa = " << ciStringLess ("Nick", "aaaa") << endl;
cout << "Nick prefix == ni = " << strPrefix ("Nick", "ni") << endl;
cout << "Nack ci prefix == ni = " << strPrefix ("Nack", "ni", true) << endl;
cout << "AABBC prefix (3) == BB = " << strPrefix ("AABBC", 3, "BB") << endl;
return 0;
} // end of main
Output
Should be true ...
Nick == nick = true
Nick
>= nick = true
Nick prefix == Ni = true
Nick ci_prefix == ni =
true
AABBC prefix (2) == BB = true
Should be false ...
Nick ==
nicky = false
Nick < aaaa = false
Nick prefix == ni = false
Nack ci
prefix == ni = false
AABBC prefix (3) == BB = false