Click here to Skip to main content
Click here to Skip to main content

MFC CString::CompareNoCase does not work as expected

, 24 May 2002 CPOL
Rate this:
Please Sign up or sign in to vote.
CString::CompareNoCase depends on locale, even though the docs say otherwise.
<!-- Add the rest of your HTML here -->

Introduction

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.

I live in Belgium where in the northern part of the country they speak Dutch while in the southern part they speak French. My application was being used in the latter part. So the users provided 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"); // French indeed

CString strTextUpper(strText);
strTextUpper.MakeUpper(); // Upper case the original 

CString strTextLower(strTextUpper);
strTextLower.MakeLower(); // Lower case the upper cased original

CString strMsg;
if ( strTextUpper.CompareNoCase(strText) )
        strMsg.Format("Original text: <%s>\n"
                      "Uppered: <%s>\n"
                      "CompareNoCase says they differ!\n"
                      "Lowered again: <%s>\n\n"
                      "Conclusion: CompareNoCase doesn't work correctly!",
                      strText, strTextUpper, strTextLower);
else
        strMsg.Format("Original:%s\nUppered:%s\nLowered again:%s\n\n"
                      "Conclusion: CompareNoCase works as expected!",
                      strText, strTextUpper, strTextLower);
AfxMessageBox(strMsg);
The output is:

So

  • I ask to uppercase a CString object
  • I ask to compare it (case insensitive) with the original one
  • Result: they differ!!!
While 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.

and for “_strupr, _wcsupr, _mbsupr” I read:

The _strupr function converts, in place, each lowercase letter in string to uppercase. The conversion is determined by the LC_CTYPE category setting of the current locale. Other characters are not affected. For more information on LC_CTYPE, see setlocale.

Workaround

This knowledge led me to two workarounds:
  1. Use CString::CollateNoCase instead of CompareNoCase:

    Result:

  2. 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");
    Result:

     

I don’t know if you agree with me, but I find this rather unnatural. I call this a bug:

  • You ask MFC to convert a CString to its uppercase variant (Man, you don’t care what locale rules it applies!)
  • You ask MFC to compare the CString it just uppercased (using “some” rules) with the original but in a case insensitive way
    (so in fact you expect it to neglect the uppercase variant and to use the original)
  • and MFC kindly tells you they differ! (:surprisedSmile | :)

Conclusion

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Geert Delmeiren
Software Developer (Senior)
Belgium Belgium
The first 5 years of my career I programmed in pure C. (Production automatisation software)
In Q4 of 1997 I switched to Visual C++/MFC.
(Headend Management system for cable operators)
 
In Q1 of 2003 I changed job and since then I'm programming in JAVA. So, now I'm looking for a JAVA site as brilliant as I found this one for C++.
 
Two years ago I started also programming in Adobe Flex.

Comments and Discussions

 
QuestionMakeUpper can throw an exception with some characters / locales PinmemberFrançoisBeretti2-Sep-11 2:56 
GeneralYour MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pinmemberahmd014-May-11 11:30 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build PinmemberGeert Delmeiren16-May-11 21:19 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build PinmemberJoxemi25-May-11 6:28 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build PinmemberGeert Delmeiren25-May-11 8:58 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build PinmemberJoxemi25-May-11 9:08 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build PinmemberGeert Delmeiren26-May-11 9:04 
Generalarticle copied to another website Pinmembercilu11-May-11 20:58 
GeneralRe: article copied to another website PinmemberGeert Delmeiren11-May-11 21:21 
GeneralThank you! PinmemberSerhiy Horobets25-Jan-10 23:11 
GeneralRe: Thank you! PinmemberGeert Delmeiren25-Jan-10 23:24 
Generalfooh.. Pinmemberpepper_vitalka10-Jul-06 21:27 
GeneralIf I am not wrong PinsussAnonymous7-Jul-05 22:54 
GeneralRe: If I am not wrong PinmemberGeert Delmeiren9-Jul-05 9:54 
Generalyou misinterpreted &quot;not affected by locale&quot; PinmemberHaraldUms2-Aug-03 23:59 
Generaluse unicode PinmemberLionel Schiepers6-Jun-02 5:24 
GeneralRe: use unicode PinmemberZac Howland3-Feb-03 5:30 
GeneralRe: use unicode PinmemberCrystal.10-Feb-03 10:46 
GeneralRe: use unicode Pinmemberpetermcwerner29-Nov-07 0:40 
Generalmy 2&#8364; Pinmemberloket26-May-02 12:58 
GeneralRe: my 2€ PinmemberGeert Delmeiren26-May-02 20:23 
GeneralRe: my 2&#8364; Pinmemberloket27-May-02 7:00 
GeneralEuropeans PinmemberS van Leent25-May-02 9:17 
GeneralRe: Europeans PinmemberGeert Delmeiren26-May-02 20:20 
GeneralThanks PinmemberNish - Native CPian24-May-02 23:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.141015.1 | Last Updated 25 May 2002
Article Copyright 2002 by Geert Delmeiren
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid