You have two strings, and you want to know if they are equal, regardless of the case of the characters. For example, “cat” is not equal to “dog,” but “Cat,” for your purposes, is equal to “cat,” “CAT,” or “caT.”
Compare the strings using the equal
standard
algorithm (defined in <algorithm>
), and supply
your own comparison function that uses the toupper
function in <cctype>
(or towupper
in <cwctype>
for wide
characters) to compare the uppercase versions of characters. Example 4-21 offers a generic solution. It
also demonstrates the use and flexibility of the STL; see the discussion below for a full
explanation.
Example 4-21. Case-insensitive string comparison
1 #include <string> 2 #include <iostream> 3 #include <algorithm> 4 #include <cctype> 5 #include <cwctype> 6 7 using namespace std; 8 9 inline bool caseInsCharCompareN(char a, char b) { 10 return(toupper(a) == toupper(b)); 11 } 12 13 inline bool caseInsCharCompareW(wchar_t a, wchar_t b) { 14 return(towupper(a) == towupper(b)); 15 } 16 17 bool caseInsCompare(const string& s1, const string& s2) { 18 return((s1.size() == s2.size()) && 19 equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareN)); 20 } 21 22 bool caseInsCompare(const wstring& s1, const wstring& s2) { 23 return((s1.size() == s2.size()) && 24 equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompareW)); 25 } 26 27 int main() { 28 string s1 = "In the BEGINNING..."; 29 string s2 = "In the beginning..."; 30 wstring ws1 = L"The END"; 31 wstring ws2 = L"the endd"; 32 33 if (caseInsCompare(s1, s2)) 34 cout << "Equal!\n"; 35 36 if (caseInsCompare(ws1, ws2)) 37 cout << "Equal!\n"; 38 }
The critical part of case-insensitive string comparison is the equality test of each
corresponding pair of characters, so let’s discuss that first. Since I am using the
equal
standard algorithm in this approach but I want
it to use my special comparison criterion, I have to create a standalone function to
handle my special comparison.
Lines 9-15 of Example 4-21 define the
functions that do the character comparison, caseInsCharCompareN
and caseInsCharCompareW
. These use toupper
and towupper
to convert each character to uppercase and then
return whether they are equal.
Once I have my comparison functions complete, it’s time to use a standard algorithm to
handle applying my comparison functions to arbitrary sequences of characters. The caseInsCompare
functions defined in lines 17-25 do just that
using equal
. There are two overloads, one for each
character type I care about. They both do the same thing, but each instantiates the
appropriate character comparison function for its character type. For this example, I
overloaded two ordinary functions, but you can achieve the same effect with templates. See
the sidebar “Should I Use a Template?” for a discussion.
equal
compares two sequence ranges for equality.
There are two versions: one that uses operator==
, and
another that uses whatever binary predicate (i.e., takes two arguments and returns a
bool
) function object you supply. In Example 4-21, caseInsCharCompareN
and W
are the binary
predicate functions.
But that’s not all you have to do—you need to compare the sizes, too. Consider equal’s declaration:
template<typename InputIterator1, typename InputIterator2, typename BinaryPredicate> bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryPredicate pred);
Let n be the distance between first1
and last1
, or in other words, the
length of the first range. equal
returns true if the
first n elements of both sequences are equal. That means that if,
given two sequences where the first n elements are equal, and the
second sequence has more than n elements, equal
will return true. Include a size check in your comparison to avoid this
false positive.
You don’t need to encapsulate this logic in a function. Your code or your client’s code can just call the algorithm directly, but it’s easier to remember and cleaner to write this:
if (caseInsCompare(s1, s2)) { // they are equal, do something
than this:
if ((s1.size() == s2.size()) && std::equal(s1.begin(), s1.end(), s2.begin(), caseInsCharCompare<char>)) { // they are equal, do something
whenever you want to do a case-insensitive string comparison.
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.