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

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


当前回答

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

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

其他回答

截至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(构建系统)

只需使用strcmp()区分大小写,使用strcmpi()或stricmp()进行不区分大小写的比较。它们都在头文件<string.h>

格式:

int strcmp(const char*,const char*);    //for case sensitive
int strcmpi(const char*,const char*);   //for case insensitive

用法:

string a="apple",b="ApPlE",c="ball";
if(strcmpi(a.c_str(),b.c_str())==0)      //(if it is a match it will return 0)
    cout<<a<<" and "<<b<<" are the same"<<"\n";
if(strcmpi(a.c_str(),b.c_str()<0)
    cout<<a[0]<<" comes before ball "<<b[0]<<", so "<<a<<" comes before "<<b;

输出

apple和apple是一样的

A在b之前,所以苹果在球之前

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

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的问题在于,你必须与boost相关联并依赖于boost。在某些情况下并不容易(例如android)。

使用char_traits意味着所有的比较都是不区分大小写的,这通常不是你想要的。

这就足够了。它应该是相当有效的。它不处理unicode或任何东西。

bool iequals(const string& a, const string& b)
{
    unsigned int sz = a.size();
    if (b.size() != sz)
        return false;
    for (unsigned int i = 0; i < sz; ++i)
        if (tolower(a[i]) != tolower(b[i]))
            return false;
    return true;
}

更新:c++ 14版本(#include <算法>):

bool iequals(const string& a, const string& b)
{
    return std::equal(a.begin(), a.end(),
                      b.begin(), b.end(),
                      [](char a, char b) {
                          return tolower(a) == tolower(b);
                      });
}

c++ 20版本使用std::ranges:

#include <ranges>
#include <algorithm>
#include <string>

bool iequals(const std::string_view& lhs, const std::string_view& rhs) {
    auto to_lower{ std::ranges::views::transform(std::tolower) };
    return std::ranges::equal(lhs | to_lower, rhs | to_lower);
}