【问题标题】:How can one properly declare char8_t for diacritical letters?如何正确声明 char8_t 为变音字母?
【发布时间】:2020-05-11 20:23:58
【问题描述】:

我尝试使用新的char8_t 类型初始化一些变音拉丁字母

constexpr char8_t french_letter_A_1 = 'À';//does not function properly

但是,Visual Studio 2019 建议我以下“由通用字符名称“\u(名称)”表示的字符不能在当前代码页中表示”,并且该字符不能正确显示;如果我尝试将字符显式声明为 u8 之一,例如:

constexpr char8_t french_letter_A_2 = u8'Â';//has error

它甚至会抛出错误“一个UTF-8字符文字值不能占用多个代码单元”;但非变音字母可以成功解释为 UTF-8 字符:

constexpr char8_t french_letter_A_0 = u8'A';//but ASCII letters are fine

我想知道如何使用 Visual C++ 正确声明 UTF-8 字符...或者我误解了 char8_t 的概念,而应该改用其他东西?

编辑:我了解到char8_t 不支持那些非 ASCII 字符。我应该改用什么字符类型?

【问题讨论】:

    标签: c++ visual-c++ utf-8 utf c++20


    【解决方案1】:

    char8_t,如 charsigned charunsigned char,大小为 1 个字节。在大多数平台(但不是全部!)上,这意味着它是一种 8 位类型,只能保存 256 个离散值。 Unicode 12.1 定义了 137,994 个字符。显然,它们不能都放在一个 char8_t 值中!

    遗憾的是,C 和 C++“字符”类型的命名很糟糕。如果我们正在设计一种具有现代术语的新语言,我们会将它们命名为code_unit 的一些变体,因为这样可以更好地反映它们的实际使用方式。 char32_t 是目前唯一保证能够为其关联字符集中的每个字符保存一个代码点值的字符类型(C 和 C++ 标准声称 wchar_t 也可以,但这与现有做法相矛盾)。

    看看你的例子,À是 U+00C0 {LATIN CAPITAL LETTER A WITH GRAVE}(或者实际上是 A U+0041 {LATIN CAPITAL LETTER A} 后面跟着 ̀ U+0300 {COMBINING GRAVE ACCENT}?Unicode 是那样很棘手)。 U+00C0 的 UTF-8 编码为 0xC3 0x80。 french_letter_A_1 应该保持什么价值?它不能同时保存两个代码单元值。如果该值是代码点,那么我们要么只能(可移植地)支持 256 个字符,要么更糟糕的是,有时char8_t 的值是代码点,有时它们是代码单元。

    现实情况是,C 和 C++ 字符文字仅限于比basic source character set 中的字符多几个字符。如果一个人正在编写仅英语的应用程序,这就足够了。但是对于现代应用程序,字符文字的用途有限。

    正如 Nicol 已经说过的,处理基本源字符集之外的大多数字符需要对字符串进行真正的文本处理。不幸的是,C 和 C++ 标准在这方面没有提供太多帮助。这是SG16 正在努力改进的地方。

    【讨论】:

      【解决方案2】:

      UTF-8 是 Unicode 代码点的编码。在 UTF-8 中,一个代码点被分解为一个或多个称为 UTF-8 代码单元的“八位字节”(8 位字)。表示 UTF-8 代码单元的 C++20 类型是char8_t

      单个char8_t 只是一个 UTF-8 代码单元。因此,它只能表示一个 UTF-8 编码只占用 1 个代码单元的 Unicode 代码点。 Visual Studio 告诉您,您尝试存储在 char8_t 中的“字符”需要超过 1 个代码单元,因此不能以这种类型存储。 UTF-8 在单个代码单元中编码的唯一 Unicode 代码点是 ASCII 代码点。

      在处理 UTF-8(或任何非 UTF-32 的 Unicode 编码)时,不要处理“字符”;你处理字符串:连续的代码单元序列。任何时候你想处理 UTF-8,你都应该使用某种基于 char8_t 的字符串类型。

      【讨论】:

      • 那么非ASCII字符应该使用什么字符类型呢?
      • @Emancipatrix:正如我所说:“在处理 UTF-8 时,你不处理“字符”;你处理字符串......你应该使用某种基于 char8_t 的字符串类型。”或者换一种说法,没有你所说的 UTF-8“字符”这样的东西。
      • 那么我应该使用wchar 来表示那些重音字母吗?如果是这样,我应该将它们声明为L'À' 或类似的东西吗?如果不是,哪种字符类型最能代表他们?
      • @Emancipatrix: ...我不知道我怎么可能让事情变得更清楚。 不要使用字符!使用字符串。在处理任何 Unicode 编码时,您不应该处理任何固定大小的“字符”。不,wchar_tchar16_t 无济于事,因为它们的许多 Unicode 代码点不适合一个 16 位字。只是停止尝试拥有角色。还有一些方法可以编写需要多个 Unicode 代码点的重音字母。 u8"À" 是您应该创建、使用和操作的对象。
      • 只是想添加一个来自非尼科尔波拉斯的人的评论,以同意尼科尔是完全正确的。如果你在做 Unicode,你就是在做字符串,根据定义。没有“Unicode 字符”这样的东西。只有字符串。我作为this blog post的作者这样说,我反问:““ﷻ”的第一个字符是什么?“ffi”的第一个字符是什么?“?”的第一个字符是什么?“?”的第一个字符是什么?”?“??‍?”的第一个字符是什么?这些问题无法回答,只有不问。
      猜你喜欢
      • 1970-01-01
      • 2017-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-12
      • 2012-05-30
      相关资源
      最近更新 更多