是的,UTF-8 编码可以与 char、string 和 stringstream 一起使用。一个 char 将包含一个 UTF-8 代码单元,其中最多可能需要四个来表示一个 Unicode 代码点。
但是,在 Microsoft 的编译器中使用 UTF-8 时存在一些问题。C++ 实现对许多事情使用“执行字符集”,例如编码字符和字符串文字。VC++总是使用系统语言环境编码作为执行字符集,而Windows不支持UTF-8作为系统语言环境编码,因此UTF-8永远不能由执行字符集。
这意味着 VC++ 从不故意生成 UTF-8 字符和字符串文字。相反,编译器必须被欺骗。
编译器将从已知的源代码编码转换为执行编码。这意味着如果编译器对源编码和执行编码都使用语言环境编码,则不会进行任何转换。如果您可以在源代码中获取 UTF-8 数据,但让编译器认为源使用区域设置编码,那么字符和字符串文字将使用 UTF-8 编码。VC++ 使用所谓的“BOM”来检测源编码,如果没有检测到 BOM,则使用区域设置编码。因此,您可以通过将所有源文件保存为“无签名的 UTF-8”来获得 UTF-8 编码的字符串文字。
这种方法有一些注意事项。首先,您不能使用具有窄字符和字符串文字的 UCN。通用字符名称必须转换为执行字符集,而不是 UTF-8。您必须按字面书写字符,使其在源代码中显示为 UTF-8,或者您可以在手动写出 UTF-8 编码的地方使用十六进制转义。其次,为了生成宽字符和字符串文字,编译器执行从源编码到宽执行字符集(在 VC++ 中始终为 UTF-16)的类似转换。由于我们在编码方面向编译器撒谎,因此它将错误地执行到 UTF-16 的转换。因此,在宽字符和字符串文字中,您不能直接使用非 ascii 字符,而必须使用 UCN 或十六进制转义。
UTF-8 是可变长度的(与 UTF-16 一样)。at()
与和一起使用的索引substr()
是代码单元,而不是字符或代码点索引。因此,如果您想要一个特定的代码单元,那么您可以像往常一样索引到字符串或数组或其他任何内容。如果您需要特定的代码点,那么您需要一个可以理解将 UTF-8 代码单元组合成代码点的库(例如 Boost Unicode 迭代器库),或者您需要将 UTF-8 数据转换为 UTF-32。如果您需要实际的用户感知字符,那么您需要一个了解代码点如何组成字符的库。我想 ICU 有这样的功能,或者你可以从 Unicode 标准实现默认字素集群边界规范。
上面对 UTF-8 的考虑只对你如何在源代码中编写 Unicode 数据很重要。它对程序的输入和输出几乎没有影响。
如果您的要求允许您选择如何进行输入和输出,那么我仍然建议使用 UTF-8 进行输入。根据您需要对输入执行的操作,您可以将其转换为易于处理的另一种编码,也可以编写处理例程以直接在 UTF-8 上工作。
如果您想通过 Windows 控制台输出任何内容,那么您将需要一个定义明确的输出模块,该模块可以具有不同的实现,因为到 Windows 控制台的国际化输出将需要与输出到 Windows 或控制台上的文件不同的实现和其他平台上的文件输出。(在其他平台上,控制台只是另一个文件,但 Windows 控制台需要特殊处理。)