rulururu

post CompareNoCase does not work as expected

July 30th, 2008

Filed under: C++, MFC — Kai @ 11:18 am

Recently I found a program of mine doing all kind of unexpected things because of CString::CompareNoCase() not returning what I expected it to return.

My application usered names containing the characters: é, è, à. Somewhere in my app I used the given name to search the corresponding object in a list. Since the given names had to be (case insensitive) unique I stored those names in uppercase format.

Afterwards I compared (in a case insensitive way) the given name with the uppercase name of each object in the list.
And that went unexpectedly wrong! Look at the following code snippet:

CString strText("élève - à la façon - château");
CString strTextUpper(strText);
strTextUpper.MakeUpper(); // Upper case the original 
 
int match = strTextUpper.CompareNoCase(strText); //does not match

For CString::CompareNoCase I read:

Compares this CString object with another string using the generic-text function _tcsicmp. The generic-text function _tcsicmp, which is defined in TCHAR.H, maps to either _stricmp, _wcsicmp, _mbsicmp depending on the character set that is defined at compile time. Each of these functions performs a case-insensitive comparison of the strings, and is not affected by locale.

While digging deeper in MSDN I discovered the existence of CString::CollateNoCase for which I read:

Compares this CString object with another string using the generic-text function _tcscoll. The generic-text function _tcscoll, which is defined in TCHAR.H, maps to either stricoll, wcsicoll, or _mbsicoll depending on the character set that is defined at compile time. Each of these functions performs a case-insensitive comparison of the strings, according to the code page currently in use.

This knowledge led me to two workarounds:

  • Use CString::CollateNoCase instead of CompareNoCase.
  • Although the help says it works independent of the locale, before calling CString::CompareNoCase set (the LC_CTYPE part of the) the locale. e.g.:
    setlocale(LC_CTYPE, "french-belgian");

Finally my confidence in MFC’s CString comparison functions isn’t great after I discovered this. And that’s why I wrote my own ever-working workaround:

int MyCompareNoCase(LPCTSTR str1, LPCTSTR str2)
{
  CString strTmp1(str1);
  CString strTmp2(str2);
  strTmp1.MakeUpper();
  strTmp2.MakeUpper();
  return strTmp1.Compare(strTmp2);
}

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

ruldrurd
Powered by WordPress, Content and Design by Kai Bellmann
Entries (RSS) and Comments (RSS)