tl;dr
使用ICU library。如果你不这样做,你的转换例程会在你可能不知道存在的情况下静默中断。
首先你要回答一个问题:你的std::string 的编码是什么?是 ISO-8859-1 吗?或者也许是 ISO-8859-8?还是 Windows 代码页 1252? 您用于将大写转换为小写的任何东西都知道吗?(或者对于超过0x7f 的字符,它是否会失败?)
如果您使用 UTF-8 (the only sane choice among the 8-bit encodings) 和 std::string 作为容器,如果您认为您仍然可以控制事物,那么您已经在欺骗自己了。您将多字节字符序列存储在不了解多字节概念的容器中,并且您可以对其执行的大多数操作也不是!即使像.substr() 这样简单的东西也可能导致无效(子)字符串,因为您在多字节序列的中间进行拆分。
一旦您尝试像std::toupper( 'ß' ) 或std::tolower( 'Σ' ) 之类的any 编码,您就有麻烦了。因为 1),该标准一次只对一个字符进行操作,所以它根本无法将 ß 转换为 SS 是正确的。并且 2),该标准一次只对一个字符进行操作,因此它无法确定 Σ 是在单词的中间(σ 是正确的),还是在末尾(ς) .另一个例子是std::tolower( 'I' ),它应该会产生不同的结果取决于语言环境 - 几乎所有你会想到i,但在土耳其ı(拉丁小写字母DOTLESS I)是正确答案(同样,在 UTF-8 编码中超过一个字节)。
因此,任何 一次对一个字符起作用的大小写转换,或者更糟糕的是,一次对一个字节 起作用的转换都被设计破坏了。 strong> 这包括目前存在的所有std:: 变体。
还有一点是,标准库 能够做什么取决于运行软件的机器上支持 的区域设置...如果您的目标语言环境在您的客户机器上不受支持,您会怎么做?
所以您真正要寻找的是一个能够正确处理所有这些的字符串类,这不是任何@987654341 @变体。
(C++11 注意:std::u16string 和 std::u32string 更好,但仍然不完美。C++20 带来了std::u8string,但所有这些都是指定 >编码。在许多其他方面,他们仍然对 Unicode 机制一无所知,例如规范化、排序规则……)
虽然 Boost 看起来不错,但在 API 方面,Boost.Locale 基本上是 ICU 的包装器。 如果 Boost 是编译 ICU 支持...如果不是,Boost.Locale 仅限于为标准库编译的语言环境支持。
相信我,获得 Boost 与 ICU 一起编译有时会很痛苦。 (包含 ICU 的 Windows 没有预编译的二进制文件,因此您必须将它们与您的应用程序一起提供,并且 会打开一个全新的蠕虫罐...)
所以我个人建议直接从马口中获得完整的 Unicode 支持并直接使用 ICU 库:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "\n";
std::cout << someUString.toUpper( "el_GR" ) << "\n";
return 0;
}
编译(本例中使用 G++):
g++ -Wall example.cpp -licuuc -licuio
这给出了:
ὀδυσσεύς
注意单词中间的Σσ转换,单词末尾的Σς转换。没有基于<algorithm> 的解决方案可以为您提供。