我正在进行一个项目,其中需要用不区分大小写的操作替换区分大小写操作。在对此进行了一些阅读之后,要考虑的数据类型是:
- Ascii字符
- 非ascii字符
- Unicode字符
如果我遗漏了清单上的任何内容,请告诉我。
以上需要单独处理吗?或者有C++的库可以在不考虑数据类型的情况下处理所有这些吗?
具体而言:
-
boost库是否对此提供支持?如果是,是否有关于如何使用API的示例或文档?
-
我了解了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▒萨尔达▒在拉马尔迪奇演出▒卡多纳牧师。小写:zo▒萨尔达▒在拉马尔迪奇打球▒卡多纳牧师。
虽然非ascii字符串似乎被转换为大写和小写,但有些文本在输出中不可见。为什么会这样?
总的来说,示例代码看起来不错吗?
我对这个问题有点惊讶。对boost case conversion
进行简单的搜索,得到了第一个条目:Usage-1.41.0-Boost,它有一个关于大小写转换的条目。
在stl case conversion
的搜索中,有一个名为lower-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。
关于Matt Jordan的评论:
这个请求的真正问题是,许多语言都有大小写转换的上下文要求——例如,希腊语中的大写西格玛0x3A3应该变成0x03C3或0x03C2,这取决于它是否在单词末尾。
如果boost库支持这一点,我会感到惊喜。你必须测试它并报告错误,如果他们没有。他们的页面上没有参考资料来说明他们是否进行了上下文大小写转换。解决方法可能是测试转换为小写并进行比较,以及转换为大写并进行比较。如果两者都是真的,那么就有一个匹配,它应该适用于99.99%的情况。
Bjarne Stroustrup的一篇有趣的论文,在这里找到,是一篇关于Locales的好文章。
关于boost,您已经有了一个非常好的答案。这里有一些补充说明:
字符编码
ASCII字符编码为7位。ISO 8859-1和windows-1252通过使用第8位,用有限的一组国际字符扩展了ASCII。
Unicode标准进一步扩展了ASCII,并在32位上进行了定义。有几种编码可用:32位的UTF32是最简单的(1个unicode字符=1个字符),但UTF16和UTF8编码允许使用较小的字符以可变大小的编码存储unicode文本。
更困难的是,不同的操作系统使用不同的约定。在linux上,wchart_t
通常是用于unicode的32位宽的字符,wstring
是基于wchar_t
的字符串,char
使用UTF8编码。在windows上,wchar_t
被定义为16位,因为windows的原生编码是UCS-2(unicode的子集),而char
通常被理解为win1252。
处理字符大小和编码
因此,要回到你的问题上来,有两个方面需要考虑:
-
存储-如果你想要一个一刀切的,你可以使用char32_t,它可以容纳ASCII和任何unicode字符。对字符串使用
basic_string<char32_t>
或u32string
,它们支持用于处理普通字符串的所有函数。或者你可以使用普通字符串,并在任何地方都使用UTF8。 -
编码-应用程序如何解释char中包含的值,以及执行转换为小写或大写等操作。这在适用的
locale
中有定义。
幸运的是,C++标准库可以处理所有这些方面:
- 管理大写字母的区域设置帮助&使用适当编码进行小写转换和测试(例如
isupper()
、isalpha()
…) - codecvt允许在各种编码之间进行转换
其他库
ICU图书馆似乎没有提供不区分病例的比较。它提供了对文本处理的支持,例如,对文本元素进行迭代,使用排序规则等
我建议继续使用标准库或boost,因为它们得到了广泛的支持。