在c++中进行不区分大小写字符串比较而不将字符串转换为全大写或全小写的最佳方法是什么?

请指出这些方法是否对unicode友好,以及它们的可移植性如何。


当前回答

无论你最终选择什么方法,如果该方法碰巧包含一些答案建议的strcmp的使用,请注意:

strcmp一般不处理Unicode数据。一般来说,它甚至不能使用基于字节的Unicode编码,比如utf-8,因为strcmp只进行逐字节的比较,而用utf-8编码的Unicode代码点可以占用超过1个字节。strcmp正确处理的唯一特定的Unicode情况是,使用基于字节的编码方式编码的字符串只包含低于U+00FF的代码点,那么每个字节的比较就足够了。

其他回答

我正试图从所有的帖子中拼凑出一个好的答案,所以帮我编辑一下:

这里有一个这样做的方法,虽然它转换字符串,并不是Unicode友好的,它应该是可移植的,这是一个加:

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
    std::string str1Cpy( str1 );
    std::string str2Cpy( str2 );
    std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
    std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
    return ( str1Cpy == str2Cpy );
}

从我所读到的,这比stricmp()更可移植,因为stricmp()实际上不是std库的一部分,而只是由大多数编译器供应商实现。

要获得真正的Unicode友好实现,似乎必须跳出std库。一个很好的第三方库是IBM ICU (Unicode国际组件)

此外,boost::iequals为进行这种比较提供了一个相当好的实用程序。

可以在Unix上使用strcasecmp,在Windows上使用stricmp。

到目前为止还没有提到的一件事是,如果您使用这些方法使用stl字符串,首先比较两个字符串的长度是有用的,因为这个信息已经在string类中提供给您了。如果您正在比较的两个字符串的长度一开始就不相同,这可以防止进行代价高昂的字符串比较。

截至2013年初,由IBM维护的ICU项目是一个很好的答案。

http://site.icu-project.org/

ICU是一个“完整的、可移植的Unicode库,密切跟踪行业标准”。对于字符串比较的特定问题,Collation对象将执行您想要的操作。

2012年年中,Mozilla项目在Firefox中采用了ICU进行国际化;您可以在这里跟踪工程讨论,包括构建系统和数据文件大小的问题:

https://groups.google.com/forum/#!topic/mozilla.dev.platform/sVVpS2sKODw https://bugzilla.mozilla.org/show_bug.cgi?id=724529(跟踪) https://bugzilla.mozilla.org/show_bug.cgi?id=724531(构建系统)

支持unicode的Visual c++字符串函数:http://msdn.microsoft.com/en-us/library/cc194799.aspx

您可能正在寻找的是_wcsnicmp

利用标准char_traits。回想一下,std::string实际上是std::basic_string<char>的类型定义,或者更明确地说,std::basic_string<char, std::char_traits<char> >。char_traits类型描述了字符如何比较,如何复制,如何转换等。您所需要做的就是在basic_string上typedef一个新字符串,并为它提供您自己的自定义char_traits,不区分大小写。

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

详情见第29期《本周大师》