Click here to Skip to main content
11,645,889 members (67,754 online)
Click here to Skip to main content

MFC CString::CompareNoCase does not work as expected

, 24 May 2002 CPOL 180.9K 31
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.

You may also be interested in...

Comments and Discussions

 
QuestionMakeUpper can throw an exception with some characters / locales Pin
FrançoisBeretti2-Sep-11 2:56
memberFrançoisBeretti2-Sep-11 2:56 
GeneralYour MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
ahmd014-May-11 11:30
memberahmd014-May-11 11:30 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
Geert Delmeiren16-May-11 21:19
memberGeert Delmeiren16-May-11 21:19 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
Joxemi25-May-11 6:28
memberJoxemi25-May-11 6:28 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
Geert Delmeiren25-May-11 8:58
memberGeert Delmeiren25-May-11 8:58 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
Joxemi25-May-11 9:08
memberJoxemi25-May-11 9:08 
GeneralRe: Your MyCompareNoCase() doesn't really solve the issue for Unicode MFC build Pin
Geert Delmeiren26-May-11 9:04
memberGeert Delmeiren26-May-11 9:04 
Generalarticle copied to another website Pin
cilu11-May-11 20:58
membercilu11-May-11 20:58 
GeneralRe: article copied to another website Pin
Geert Delmeiren11-May-11 21:21
memberGeert Delmeiren11-May-11 21:21 
GeneralThank you! Pin
Serhiy Horobets25-Jan-10 23:11
memberSerhiy Horobets25-Jan-10 23:11 
GeneralRe: Thank you! Pin
Geert Delmeiren25-Jan-10 23:24
memberGeert Delmeiren25-Jan-10 23:24 
Generalfooh.. Pin
pepper_vitalka10-Jul-06 21:27
memberpepper_vitalka10-Jul-06 21:27 
GeneralIf I am not wrong Pin
Anonymous7-Jul-05 22:54
sussAnonymous7-Jul-05 22:54 
GeneralRe: If I am not wrong Pin
Geert Delmeiren9-Jul-05 9:54
memberGeert Delmeiren9-Jul-05 9:54 
Generalyou misinterpreted &quot;not affected by locale&quot; Pin
HaraldUms2-Aug-03 23:59
memberHaraldUms2-Aug-03 23:59 
Generaluse unicode Pin
Lionel Schiepers6-Jun-02 5:24
memberLionel Schiepers6-Jun-02 5:24 
GeneralRe: use unicode Pin
Zac Howland3-Feb-03 5:30
memberZac Howland3-Feb-03 5:30 
GeneralRe: use unicode Pin
Crystal.10-Feb-03 10:46
memberCrystal.10-Feb-03 10:46 
GeneralRe: use unicode Pin
petermcwerner29-Nov-07 0:40
memberpetermcwerner29-Nov-07 0:40 
Generalmy 2&#8364; Pin
loket26-May-02 12:58
memberloket26-May-02 12:58 
GeneralRe: my 2€ Pin
Geert Delmeiren26-May-02 20:23
memberGeert Delmeiren26-May-02 20:23 
GeneralRe: my 2&#8364; Pin
loket27-May-02 7:00
memberloket27-May-02 7:00 
GeneralEuropeans Pin
S van Leent25-May-02 9:17
memberS van Leent25-May-02 9:17 
GeneralRe: Europeans Pin
Geert Delmeiren26-May-02 20:20
memberGeert Delmeiren26-May-02 20:20 
GeneralThanks Pin
Nish - Native CPian24-May-02 23:11
memberNish - 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 | Terms of Use | Mobile
Web03 | 2.8.150731.1 | Last Updated 25 May 2002
Article Copyright 2002 by Geert Delmeiren
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid