不区分大小写的操作

时间:2016-03-24 14:13:44

标签: c++ case-insensitive icu

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

  1. Ascii字符
  2. 非ascii字符
  3. Unicode字符
  4. 如果我错过了列表中的任何内容,请告诉我。

    上面是否需要单独处理或者是否有C ++库可以处理它们而不涉及数据类型?

    具体做法是:

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

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

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

      谢谢!

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

      #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 string:Test String。 小写:测试字符串。

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

      Non-Ascii string:Zo▒Salda▒a在Lamaldici▒ndelpadre Cardona中出场。 小写:zo▒salda▒a在lamaldici▒ndelpadre cardona中播放。

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

      总的来说,示例代码看起来不错吗?

2 个答案:

答案 0 :(得分:2)

我对这个问题感到有些惊讶。对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,则可能需要将locals用于代码页。 Unicode应该没有问题AFAIK。

关于马特乔丹的评论:

  

此请求的真正问题是许多语言都具有案例转换的上下文要求 - 例如希腊语中的大写sigma 0x3A3应该变为0x03C3或0x03C2,具体取决于它是否在单词的末尾。

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

Bjarne Stroustrup撰写的一篇有趣的论文,发现here,是关于Locales的好读物。

答案 1 :(得分:1)

你已经对提升有了很好的答案。这里有一些补充说明:

字符编码

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

Unicode标准进一步扩展了ASCII,并在32位上定义。有几种编码可供使用:32位上的UTF32是最简单的(1个unicode字符= 1个字符),但UTF16UTF8编码允许使用较小的编码来存储Unicode文本字符。

为了使其更加困难,不同的操作系统使用不同的约定。在linux上,wchart_t通常是用于unicode的32位宽字符,wstring是基于wchar_t的字符串,char使用UTF8编码。在Windows wchar_t上定义为16位,因为Windows&#39;本机编码是UCS-2(unicode的子集),char通常被理解为win1252。

处理字符大小和编码

因此,要回顾您的问题,需要考虑两个方面:

  • 存储 - 如果你想要一个适合所有人的大小,你可以使用char32_t和任何unicode字符一样保存ASCII。并使用basic_string<char32_t>u32string作为字符串,它支持您用于处理普通字符串的所有函数。或者你可以使用普通字符串并遵守UTF 8 everywhere

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

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

  • 区域设置有助于管理uppercase&amp;使用适当的编码
  • 进行小写转换和测试(例如isupper()isalpha(),...)
  • codecvt允许在各种encondings之间进行转换

其他图书馆

ICU库似乎不提供不区分大小写的比较。它为文本处理提供支持,例如,使用排序规则等迭代文本元素。

我建议继续使用标准库或提升,因为他们享有广泛的支持。