views:

1815

answers:

8

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?

A: 

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
  }
};
Chris Harris
I think a Standard Library solution was asked for.
anon
+2  A: 

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

Sahasranaman MS
+2  A: 

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);

    if(stringA == stringB)
        return true;
    else
        return false;
}

wstring stringA = "foo";
wstring stringB = "FOO";
if(comparei(stringA , stringB))
{
    // strings match
}
Callum
that if(stringA == stringB) forces me to leave a comment! :) should be return (stringA == stringB)
Idan K
This solution will not work in several locales, in some languages when you convert to uppercase and then back you get different strings.
Stan
+1  A: 

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

Magnus Skog
Example for those of us that do not have that book would be nice.
Stan
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
+6  A: 

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 str1 = "hello, world!";
std::wstring str2 "HELLO, WORLD!";

if (boost::iequals(str1, str2))
{
    // Strings are identical
}
Stan
A: 
#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
+1  A: 

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;
}
AraK
+1. (second[i] ^ 32) is interesting. I never knew this was how ascii was designed!
Sahasranaman MS
A: 

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ș