Use the standard algorithms transform
and search
, defined in <algorithm>
, along with your own special character comparison
functions, similar to the approach presented in. Example 4-22 shows how to do this.
Example 4-22. Case-insensitive string search
#include <string> #include <iostream> #include <algorithm> #include <iterator> #include <cctype> using namespace std; inline bool caseInsCharCompSingle(char a, char b) { return(toupper(a) == b); } string::const_iterator caseInsFind(string& s, const string& p) { string tmp; transform(p.begin(), p.end(), // Make the pattern back_inserter(tmp), // upper-case toupper); return(search(s.begin(), s.end(), // Return the iter- tmp.begin(), tmp.end(), // ator returned by caseInsCharCompSingle)); // search } int main() { string s = "row, row, row, your boat"; string p = "YOUR"; string::const_iterator it = caseInsFind(s, p); if (it != s.end()) { cout << "Found it!\n"; } }
By returning an iterator that refers to the element in the target string where the pattern string starts, you ensure ease of compatibility with other standard algorithms since most of them accept iterator arguments.
Example 4-22 demonstrates the usual
mode of operation when working with standard algorithms. Create the functions that do the
work, then plug them into the most appropriate algorithms as function objects. The
charInsCharCompSingle
function does the real work
here but, unlike Example 4-21, this
character comparison function only uppercases the first argument.
This is because a little later in caseInsFind
, I
convert the pattern string to all uppercase before using it to search to avoid having to
uppercase each pattern character multiple times.
Once the comparison function is out of the way, use the transform
and search
standard algorithms
to do two things. Use transform
to uppercase the entire
pattern (but not the target string). After that, use search
with the comparison function to find the location of the
substring.
Remember that standard algorithms operate on sequences, not just
strings. They are general algorithms that operate on, primarily but not exclusively, the
standard containers, but they make no assumptions about the contents of the containers.
All the standard algorithms care about is that you supply a comparison function (or if
not, they use the default operator
s) that somehow
compares two elements and returns a bool
indicating
whether the test is true or false.
There is one thing I should point out that looks odd in Example 4-22. You can see that caseInsCompare
returns a const_iterator
, as in
string::const_iterator caseInsFind(const string& s, const string& p)
What if you want to modify the element that the returned iterator points to? This is a
reasonable request. The reason it is const
is because
the strings being passed into caseInsFind
are const
, and therefore you can’t get a non-const
iterator to a const
string. If you want an iterator you can use to modify the string, remove the const
from the parameters and change the function declaration
to
return a string::iterator
instead.
Get C++ Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.