不区分大小写的操作

Case insensitive operations

我正在处理一个项目,其中需要将区分大小写的操作替换为不区分大小写的操作。在对此进行了一些阅读之后,要考虑的数据类型是:

  1. Ascii 字符
  2. 非 ascii 字符
  3. Unicode 字符

如果我遗漏了列表中的任何内容,请告诉我。

以上是否需要单独处理,或者是否有 C++ 库可以处理所有这些而不考虑数据类型?

具体来说:

  1. boost库是否提供对此的支持?如果有,是否有关于如何使用 API 的示例或文档?

  2. 我了解了 IBM 的 Unicode 国际组件 (ICU)。这是一个支持不区分大小写操作的库吗?如果有,是否有关于如何使用 API 的示例或文档?

最后,上述(和其他)方法中哪种更好,为什么?

谢谢!

根据评论和回答,我写了一个示例程序来更好地理解这一点:

#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

using namespace std;

void ascii_to_lower(string& str)
{
     std::locale loc;
     std::cout << "Ascii string: " << str;
     std::cout << "Lower case: ";

     for (std::string::size_type i=0; i<str.length(); ++i)
         std::cout << std::tolower(str[i],loc);
     return;
}

void non_ascii_to_lower(void)
{
    std::locale::global(std::locale("en_US.UTF-8"));
    std::wcout.imbue(std::locale());
    const std::ctype<wchar_t>& f = std::use_facet<std::ctype<wchar_t> >(std::local
    std::wstring str = L"Zoë Saldaña played in La maldición del padre Cardona.";

    std::wcout << endl << "Non-Ascii string: " << str << endl;

    f.tolower(&str[0], &str[0] + str.size());

    std::wcout << "Lower case: " << str << endl;

    return;
}

void non_ascii_to_upper(void)
{
    std::locale::global(std::locale("en_US.UTF-8"));
    std::wcout.imbue(std::locale());
    const std::ctype<wchar_t>& f = std::use_facet<std::ctype<wchar_t> >(std::local
    std::wstring str = L"¥£ªÄë";

    std::wcout << endl << "Non-Ascii string: " << str << endl;

    f.toupper(&str[0], &str[0] + str.size());

    std::wcout << "Upper case: " << str << endl;

    return;
}

int main ()
{
    string str="Test String.\n";

    ascii_to_lower(str);
    non_ascii_to_upper();
    non_ascii_to_lower();

    return 0;
}

输出为:

Ascii 字符串:测试字符串。 小写:测试字符串。

非Ascii字符串:▒▒▒▒▒ 大写:▒▒▒▒▒

非 Ascii 字符串:Zo▒ Salda▒a 在 La maldici▒n del padre Cardona 中演奏。 小写字母:zo▒ salda▒a 在 la maldici▒n del padre cardona 演出。

非 ascii 字符串,尽管似乎已转换为大小写,但某些文本在输出中不可见。为什么是这样?

总的来说,示例代码看起来还可以吗?

这个问题让我有点吃惊。对 boost case conversion 的简单搜索作为第一个条目出现:Usage - 1.41.0 - Boost 其中有一个关于大小写转换的条目。

搜索 stl case conversion 有一个条目 tolower - C++ Reference - Cplusplus.com,它还显示了如何使用 STL 进行转换。

要进行不区分大小写的搜索,请将两者转换为小写或大写并进行比较。

来自 boost.org 的代码示例:

string str1("HeLlO WoRld!");
to_upper(str1); // str1=="HELLO WORLD!"

示例来自 Cplusplus.com:

// tolower example (C++)
#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

int main ()
{
  std::locale loc;
  std::string str="Test String.\n";
  for (std::string::size_type i=0; i<str.length(); ++i)
    std::cout << std::tolower(str[i],loc);
  return 0;
}

对于ASCII字符(ASCII值<128的字符),应该没有问题。如果您正在使用 MCBS,您可能需要对代码页使用局部变量。 Unicode 应该没有问题 AFAIK.

关于马特乔丹的评论:

The real issue with this request is that many languages have contextual requirements for case conversion - e.g. capital sigma 0x3A3 in Greek should become either 0x03C3 or 0x03C2, depending on whether it is at the end of a word or not.

如果 boost 库支持这个,我会感到惊喜。如果他们不这样做,您将不得不对其进行测试并报告错误。他们的页面上没有任何参考说明他们是否进行了任何上下文大小写转换。解决方法可能是测试转换为小写和比较,以及转换为大写和比较。如果其中一个为真,则存在一个匹配项,它应该适用于 99.99% 的情况。

发现了 Bjarne Stroustrup 的一篇有趣的论文 here,是关于区域设置的好读物。

你已经很好地回答了boost。这里有一些补充说明:

字符编码

ASCII 字符以 7 位编码。 ISO 8859-1 and windows-1252 通过使用第 8 位,用一组有限的国际字符扩展 ASCII。

Unicode standard extends ASCII even further and is defined on 32 bit. Several encodings are available: UTF32 on 32 bits is the easiest (1 unicode character = 1 char), but UTF16 and UTF8 编码允许使用较小的字符存储具有可变大小编码的 Unicode 文本。

更难的是,不同的操作系统使用不同的约定。在linux上,wchart_t一般是用于unicode的32位宽的char,wstring是基于wchar_t的字符串,char使用UTF8编码.在windows上wchar_t被定义为16位,因为windows的原生编码是UCS-2(unicode的一个子集),而char一般理解为win1252。

处理字符大小和编码

所以回到你的问题,有两个方面需要考虑:

  • 存储空间 - 如果您想要一机多用,可以使用 char32_t that can hold as well ASCII as any unicode character. And use a basic_string<char32_t> or u32string for strings, which support all the functions you are used to handle for normal strings. Or you can you could use normal strings and adhere to UTF 8 everywhere

  • 编码 - 您的应用如何解释字符中包含的值,以及如何执行转换为小写或大写等操作。这在适用的 locale 中定义。

幸运的是,C++ 标准库可以应对所有这些方面:

  • locale 使用适当的编码
  • 帮助管理 uppercase 和小写转换和测试(例如 isupper()isalpha()、...)
  • codecvt 允许在各种编码之间进行转换

其他库

ICU 库似乎不提供不区分大小写的比较。它提供对文本处理的支持,例如,遍历文本元素、使用归类排序等。

我建议继续使用标准库或 boost,因为它们得到了广泛的支持。