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

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


当前回答

如果是在POSIX系统上,可以使用strcasecmp。不过,这个函数不是标准C语言的一部分,在Windows上也不可用。这将对8位字符执行不区分大小写的比较,只要区域设置为POSIX。如果区域设置不是POSIX,则结果是未定义的(因此它可能进行本地化比较,也可能不进行)。没有宽字符的等效版本。

如果做不到这一点,大量历史上的C库实现都有stricmp()和strnicmp()函数。Windows上的Visual c++通过在它们前面加上下划线来重命名它们,因为它们不是ANSI标准的一部分,所以在那个系统中它们被称为_stricmp或_strnicmp。一些库可能还具有宽字符或多字节等效函数(通常命名为wcsicmp, mbcsicmp等)。

C和c++在很大程度上都不了解国际化问题,所以除了使用第三方库之外,这个问题没有好的解决方案。如果需要用于C/ c++的健壮库,请参阅IBM ICU (Unicode国际组件)。ICU适用于Windows和Unix系统。

其他回答

如果是在POSIX系统上,可以使用strcasecmp。不过,这个函数不是标准C语言的一部分,在Windows上也不可用。这将对8位字符执行不区分大小写的比较,只要区域设置为POSIX。如果区域设置不是POSIX,则结果是未定义的(因此它可能进行本地化比较,也可能不进行)。没有宽字符的等效版本。

如果做不到这一点,大量历史上的C库实现都有stricmp()和strnicmp()函数。Windows上的Visual c++通过在它们前面加上下划线来重命名它们,因为它们不是ANSI标准的一部分,所以在那个系统中它们被称为_stricmp或_strnicmp。一些库可能还具有宽字符或多字节等效函数(通常命名为wcsicmp, mbcsicmp等)。

C和c++在很大程度上都不了解国际化问题,所以除了使用第三方库之外,这个问题没有好的解决方案。如果需要用于C/ c++的健壮库,请参阅IBM ICU (Unicode国际组件)。ICU适用于Windows和Unix系统。

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

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

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

如果您必须更频繁地将源字符串与其他字符串进行比较,一个优雅的解决方案是使用正则表达式。

std::wstring first = L"Test";
std::wstring second = L"TEST";

std::wregex pattern(first, std::wregex::icase);
bool isEqual = std::regex_match(second, pattern);

如果你不想使用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;
}

Boost::iequals在string的情况下不兼容utf-8。 你可以使用boost::locale。

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;

Primary -- ignore accents and character case, comparing base letters only. For example "facade" and "Façade" are the same. Secondary -- ignore character case but consider accents. "facade" and "façade" are different but "Façade" and "façade" are the same. Tertiary -- consider both case and accents: "Façade" and "façade" are different. Ignore punctuation. Quaternary -- consider all case, accents, and punctuation. The words must be identical in terms of Unicode representation. Identical -- as quaternary, but compare code points as well.