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

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


当前回答

迟来的派对,但这里有一个变种,使用std::locale,因此正确处理土耳其语:

auto tolower = std::bind1st(
    std::mem_fun(
        &std::ctype<char>::tolower),
    &std::use_facet<std::ctype<char> >(
        std::locale()));

提供一个函子,使用活动区域设置将字符转换为小写,然后可以通过std::transform生成小写字符串:

std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);

这也适用于基于wchar_t的字符串。

其他回答

你说的是一个愚蠢的不区分大小写的比较还是一个完全标准化的Unicode比较?

哑比较不会找到可能相同但二进制不相等的字符串。

例子:

U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).

都是等价的,但它们也有不同的二进制表示。

也就是说,Unicode标准化应该是必读的,特别是如果您计划支持韩文,Thaï和其他亚洲语言。

此外,IBM几乎为大多数优化的Unicode算法申请了专利,并将它们公开提供。它们还维护一个实现:IBM ICU

看到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

str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

如果你不能使用boost,你可以在c++ 14中使用上面的代码。对于宽字符,必须使用std::towlower。

如果你不想使用Boost库,那么这里有一个解决方案,它只使用c++标准io头。

#include <iostream>

struct iequal
{
    bool operator()(int c1, int c2) const
    {
        // case insensitive comparison of two characters.
        return std::toupper(c1) == std::toupper(c2);
    }
};

bool iequals(const std::string& str1, const std::string& str2)
{
    // use std::equal() to compare range of characters using the functor above.
    return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());
}

int main(void)
{
    std::string str_1 = "HELLO";
    std::string str_2 = "hello";

    if(iequals(str_1,str_2))
    {
        std::cout<<"String are equal"<<std::endl;   
    }

    else
    {
        std::cout<<"String are not equal"<<std::endl;
    }


    return 0;
}

我有使用Unicode库的International Components的丰富经验——它们非常强大,并提供了转换、区域支持、日期和时间呈现、大小写映射(您似乎不想要)和排序(其中包括大小写和重音不敏感比较)的方法。我只使用了c++版本的库,但它们似乎也有Java版本。

方法可以执行标准化的比较,如@Coincoin所述,甚至可以解释地区-例如(这是一个排序的例子,不是严格的相等),传统的西班牙语(在西班牙),字母组合“ll”在“l”和“m”之间排序,因此“lz”<“ll”<“ma”。