25

I am sure this would have been asked before but couldn't find it. Is there any built in (i.e. either using std::wstring's methods or the algorithms) way to case insensitive comparison the two wstring objects?

Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 6
    Note, that case-insensitive comparisons are locale-dependent. – avakar Jul 01 '09 at 09:24
  • 1
    see http://stackoverflow.com/questions/11635/case-insensitive-string-comparison-in-c , I'd recommend either the Boost solution or extracting c_str and using wcscasecmp/_wcsicmp – Hasturkun Jul 01 '09 at 09:35
  • @Hasturkun: Thanks for the link. I vaguely remembered reading this on SO. – Naveen Jul 01 '09 at 10:04

8 Answers8

32

If you don't mind being tied to Microsoft implementation you can use this function defined in <string.h>

int _wcsnicmp(
   const wchar_t *string1,
   const wchar_t *string2,
   size_t count 
);

But if you want best performance/compatibility/functionality ratio you will probably have to look at boost library (part of it is stl anyway). Simple example (taken from different answer to different question):

#include <boost/algorithm/string.hpp>

std::wstring wstr1 = L"hello, world!";
std::wstring wstr2 = L"HELLO, WORLD!";

if (boost::iequals(wstr1, wstr2))
{
    // Strings are identical
}
Community
  • 1
  • 1
Stan
  • 2,487
  • 18
  • 27
6

Using the standard library:

bool comparei(wstring stringA , wstring stringB)
{
    transform(stringA.begin(), stringA.end(), stringA.begin(), toupper);
    transform(stringB.begin(), stringB.end(), stringB.begin(), toupper);

    return (stringA == stringB);
}

wstring stringA = "foo";
wstring stringB = "FOO";
if(comparei(stringA , stringB))
{
    // strings match
}
piedar
  • 2,599
  • 1
  • 25
  • 37
Callum
  • 2,063
  • 2
  • 14
  • 12
  • 12
    that if(stringA == stringB) forces me to leave a comment! :) should be return (stringA == stringB) – Idan K Jul 01 '09 at 09:37
  • 4
    This solution will not work in several locales, in some languages when you convert to uppercase and then back you get different strings. – Stan Jul 01 '09 at 09:40
  • 3
    You didn't just compare the strings, you have actually made both strings UPPERCASE regardless of the outcome. Try writing a method with the signature `bool compare(const wstring stringA, const wstring stringB)`, then fix this algorithm. – Zak Jul 12 '14 at 21:14
  • 1
    Should have used towupper. – Nayan Oct 22 '15 at 16:52
5

You can use std::tolower() to convert the strings to lowercase or use the function wcscasecmp to do a case insensitive compare on the c_str()'s.

Here is a comparison functor you can use directly as well:

struct ci_less_w
{
  bool operator() (const std::wstring & s1, const std::wstring & s2) const
  {
      #ifndef _WIN32
            return wcscasecmp(s1.c_str(), s2.c_str()) < 0;
      #else
            return _wcsicmp(s1.c_str(), s2.c_str()) < 0;
      #endif
  }
};
Azeem
  • 11,148
  • 4
  • 27
  • 40
Chris Harris
  • 4,705
  • 3
  • 24
  • 22
2

You could use the boost string algorithms library. Its a header only library as long as you're not going to do regex. So you can do that very easily.

http://www.boost.org/doc/libs/1_39_0/doc/html/string_algo.html

Sahas
  • 10,637
  • 9
  • 41
  • 51
2
#include <algorithm>
#include <string>
#include <cstdio>


 bool icase_wchar_cmp(wchar_t a, wchar_t b)
{
  return std::toupper(a) == std::toupper(b);
}


bool icase_cmp(std::wstring const& s1, std::wstring const& s2)
{
  return (s1.size() == s2.size()) &&
             std::equal(s1.begin(), s1.end(), s2.begin(),
                              icase_wchar_cmp);
}



int main(int argc, char** argv)
{
  using namespace std;

  wstring str1(L"Hello"), str2(L"hello");

  wprintf(L"%S and %S are %S\n", str1.c_str(), str2.c_str(),
              icase_cmp(str1,str2) ? L"equal" : L"not equal");

  return 0;
}
Maik Beckmann
  • 5,637
  • 1
  • 23
  • 18
2

Talking about English right ?! though I would go with my lovely Boost :)

bool isequal(const std::wstring& first, const std::wstring& second)
{
    if(first.size() != second.size())
        return false;

    for(std::wstring::size_type i = 0; i < first.size(); i++)
    {
        if(first[i] != second[i] && first[i] != (second[i] ^ 32))
            return false;
    }

    return true;
}
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • 4
    +1. (second[i] ^ 32) is interesting. I never knew this was how ascii was designed! – Sahas Jul 01 '09 at 11:38
  • 3
    This will consider `[` to be the same as `{`, and `*` to be the same as a newline, along with many other such inaccuracies. Besides, assuming English when dealing with wide strings is almost certainly wrong. – interjay Jun 11 '13 at 13:38
1

If you need that the string will always make case insensitive comparation (when using operators == or !=), then a possible elegant solution is to redefine char_traits::compare method.

Define your own structure. Example

struct my_wchar_traits: public std::char_traits< wchar_t>
{
    static int compare( const char_type* op1, const char_type* op2, std::size_t num) 
    {
       // Implementation here... any of the previous responses might help...
    } 
};

Then, define your own case insensitive string:

typedef std::basic_string< wchar_t, my_wchar_traits> my_wstring;
Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
-1

You can use mismatch() or lexicographical_compare(). This is suggested by Scott Meyers in Effecitve STL, item 35.

rtn
  • 127,556
  • 20
  • 111
  • 121
  • 2
    Example for those of us that do not have that book would be nice. – Stan Jul 01 '09 at 10:01
  • 2
    Note that neither of these functions will compare case-insensitively by default. You would still have to write a function that compares characters case-insensitively and pass it to those functions. – Geerad Jul 01 '09 at 10:26