14

我正在编写一个需要能够处理所有语言文本的程序。我的理解是 UTF-8 可以完成这项工作,但我遇到了一些问题。

我可以说 UTF-8 可以简单地存储char在 C++ 中吗?如果是这样,为什么我在使用带有char,stringstringstream:的程序时会收到以下警告warning C4566: character represented by universal-character-name '\uFFFD' cannot be represented in the current code page (1252)wchar_t(当我使用,wstring和时,我没有得到那个错误wstringstream。)

此外,我知道 UTF 是可变长度的。当我使用atorsubstr字符串方法时,我会得到错误的答案吗?

4

3 回答 3

18

要使用 UTF-8 字符串文字,您需要在它们前面加上前缀u8,否则您将获得实现的字符集(在您的情况下,它似乎是 Windows-1252):u8"\uFFFD"是以 UTF-8 表示的以空字符结尾的字节序列替换字符 (U+FFFD)。它有类型char const[4]

由于 UTF-8 具有可变长度,所有类型的索引都将在代码单元中进行索引,而不是代码点。不可能对 UTF-8 序列中的代码点进行随机访问,因为它是可变长度的。如果你想要随机访问,你需要使用固定长度的编码,比如 UTF-32。为此,您可以U在字符串上使用前缀。

于 2012-08-20T15:29:02.223 回答
11

是的,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 控制台需要特殊处理。)

于 2012-08-20T16:00:29.363 回答
1

您收到警告的原因\uFFFD是您试图放入FF FD单个字节,因为正如您所指出的,UTF-8 适用于chars 并且是可变长度的。

如果你使用ator substr,你可能会得到错误的答案,因为这些方法计算一个字节应该是一个字符。UTF-8 并非如此。值得注意的是,使用at,您最终可能会得到一个字符序列的单个字节;使用substr,您可能会破坏一个序列并以无效的 UTF-8 字符串结尾(它将以 �, 开头或结尾,\uFFFD与您显然尝试使用的相同,并且损坏的字符会丢失)。

我建议您使用wchar来存储 Unicode 字符串。由于类型至少为 16 位,因此一个“单元”可以容纳更多的字符。

于 2012-08-20T15:28:28.253 回答