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

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


当前回答

看到std:: lexicographical_compare:

// lexicographical_compare example
#include <iostream>  // std::cout, std::boolalpha
#include <algorithm>  // std::lexicographical_compare
#include <cctype>  // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
    return std::tolower(c1) < std::tolower(c2);
}

int main () {
    char foo[] = "Apple";
    char bar[] = "apartment";

    std::cout << std::boolalpha;

    std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";

    std::cout << "Using default comparison (operator<): ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
    std::cout << '\n';

    std::cout << "Using mycomp as comparison object: ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
    std::cout << '\n';

    return 0;
}

Demo

其他回答

假设您正在寻找一个方法,而不是一个已经存在的神奇函数,坦率地说,没有更好的方法。对于有限的字符集,我们都可以使用聪明的技巧编写代码片段,但在一天结束时,你必须转换字符。

这种转换的最佳方法是在比较之前进行转换。当涉及到编码方案时,这为您提供了很大的灵活性,而实际的比较操作符应该忽略这一点。

当然,你可以在你自己的字符串函数或类后面“隐藏”这个转换,但你仍然需要在比较之前转换字符串。

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

您可能正在寻找的是_wcsnicmp

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

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

对于我基本的不区分大小写的字符串比较需求,我宁愿不使用外部库,也不想要一个与所有其他字符串不兼容的不区分大小写特征的单独字符串类。

所以我想到的是:

bool icasecmp(const string& l, const string& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](string::value_type l1, string::value_type r1)
                { return toupper(l1) == toupper(r1); });
}

bool icasecmp(const wstring& l, const wstring& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](wstring::value_type l1, wstring::value_type r1)
                { return towupper(l1) == towupper(r1); });
}

一个简单的函数,一个重载char,另一个重载whar_t。不使用任何非标准的东西,所以应该在任何平台上都很好。

相等性比较不会考虑像变长编码和Unicode规范化这样的问题,但据我所知,basic_string不支持这一点,而且这通常不是一个问题。

在需要对文本进行更复杂的词典操作的情况下,您只需使用像Boost这样的第三方库,这是可以预料到的。

对于非unicode版本,我的第一个想法是这样做的:

bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
    if (str1.size() != str2.size()) {
        return false;
    }
    for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
        if (tolower(static_cast<unsigned char>(*c1)) != tolower(static_cast<unsigned char>(*c2))) {
            return false;
        }
    }
    return true;
}