7

我们编写一个C++应用程序,需要知道这一点:

文本编码是否是UTF8从字节到字符的单射映射,这意味着每个字符(字母......)都只以一种方式编码?因此,例如字母 'Ž' 不能同时编码为 3231 和 32119。

4

5 回答 5

14

这在很大程度上取决于您认为“字母”是什么。

UTF8 基本上是 Unicode 的一小部分。

基本上至少有三个级别:字节、代码点和字素簇。根据某种编码,一个代码点可以编码为一个或多个字节,如 UTF8、UTF16 或 UTF32。这种编码是唯一的(因为所有替代方式都被声明为无效)。然而,代码点并不总是字形,因为存在所谓的组合字符。这种组合字符跟在基本字符之后,正如它们的名字所说,与基本字符组合在一起。例如,组合字符 U+0308 COMBINING DIAERESIS 将分音符 (¨) 放在前面的字母之上。因此,如果它跟在例如 a (U+0061 LATIN SMALL LETTER A) 之后,则结果是 ä。然而,字母 ä 也有一个代码点(U+00E4 拉丁小写字母 A 带分音符号),

因此,每个代码点都有一个有效的 UTF 8 编码(例如,U+0061 是“\141”,U+0308 是“\314\210”,U+00e4 是“\303\244”,但字母 ä 是由代码点序列 U+0061 U+0308(即 UTF8 中的字节序列“\141\314\210”)和单个代码点 U+00E4(即字节序列“\303\244”)编码。

更糟糕的是,由于 Unicode 制造商决定组合字母在基本字母之后而不是在它之前,所以在看到下一个代码点之前,您无法知道您的字形是否完整(如果它不是组合代码点,您的信写完了)。

于 2011-11-13T21:12:05.790 回答
7

有效的 UTF-8 确实对每个字符进行了唯一编码。但是,存在符合一般编码方案的所谓超长序列,但根据定义是无效的,因为只有最短的序列可以用于对字符进行编码。

例如,UTF-8 有一个衍生版本,称为修改后的 UTF-8,它将 NUL 编码为超长序列0xC0 0x80,而不是0x00获得与以空字符结尾的字符串兼容的编码。

如果您询问的是字素簇(即用户感知的字符)而不是字符,那么即使是有效的 UTF-8 也是模棱两可的。但是,Unicode 定义了几种不同的规范化形式,如果您将自己限制为规范化字符串,那么 UTF-8 确实是单射的。

有点离题:这是我想出的一些 ASCII 艺术作品,以帮助可视化character的不同概念。垂直分离的是抽象机器层次。随意想出更好的名字...

                         [user-perceived characters]<-+
                                      ^               |
                                      |               |
                                      v               |
            [characters] <-> [grapheme clusters]      |
                 ^                    ^               |
                 |                    |               |
                 v                    v               |
[bytes] <-> [codepoints]           [glyphs]<----------+

回到主题:该图还显示了使用字节比较抽象字符串时可能出现的问题。特别是(假设 UTF-8),程序员需要确保

  • 字节序列有效,即不包含超长序列或编码非字符代码点
  • 字符序列被规范化,因此等效的字素簇具有唯一的表示
于 2011-11-13T21:11:28.783 回答
3
于 2011-11-13T21:13:11.870 回答
2

是的。UTF-8 只是编码 Unicode 字符的标准方式。这样做是为了只有一种方法可以对每个 Unicode 字符进行编码。

有点离题:知道某些字符的外观(与人类)非常相似可能很有用,但它们仍然不同 - 例如,西里尔文中有一个看起来与“/”非常相似的符号。

于 2011-11-13T20:55:34.237 回答
0

是的,有点。如果使用得当,每个 unicode 代码点只能以 UTF-8 的一种方式编码,但这部分是因为要求任何字符只应使用最短的适用 UTF-8 字节序列。

但是,如果不是出于此要求,用于对字符进行编码的方法可以以不止一种方式对许多字符进行编码 - 尽管不合适,但在某些情况下会这样做。

例如,“Z”可以被编码为0x5aor {0xa1, 0x9a}(除其他外),尽管唯一0x5a被认为是正确的,因为它是最短的序列。

于 2011-11-13T21:10:23.993 回答