是UTF8内射映射?

时间:2011-11-13 20:53:03

标签: c++ c unicode utf-8 unicode-normalization

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

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

5 个答案:

答案 0 :(得分:13)

这在很大程度上取决于你认为的“信件”。

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

基本上至少有三个级别:字节,代码点和Grapheme集群。 根据特定编码,如UTF8,UTF16或UTF32,代码点可以编码为一个或多个字节。此编码是唯一的(因为所有替代方法都被声明为无效)。但是,代码点并不总是字形,因为存在所谓的组合字符。这样的组合字符遵循基本字符,并且如其名称所示,与基本字符组合。例如,有一个组合字符U + 0308 COMBINING DIAERESIS,它将一个分音符(¨)置于前一个字母之上。所以如果它遵循例如a(U + 0061 LATIN SMALL LETTER A),结果是ä。然而,字母ä(U + 00E4 LATIN SMALL LETTER A WITH DIAERESIS)也有一个代码点,所以这意味着代码序列U + 0061 U + 0308和U + 00E4描述了相同的字母。

因此,每个代码点都有一个有效的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制造商决定组合字母跟随基本字母而不是在它之前,你不知道你的字形是否完整,直到你看到下一个代码点(如果它不是组合代码点,则表示您的信件已完成)。

答案 1 :(得分:6)

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

例如,UTF-8的衍生物称为 modified UTF-8,它将NUL编码为超长序列0xC0 0x80而不是0x00来获取编码与以null结尾的字符串兼容。

如果您要询问字形集群(即用户感知的字符)而不是字符,那么即使有效的UTF-8也不明确。但是,Unicode定义了几个不同的normalization forms,如果你将自己局限于规范化的字符串,那么UTF-8确实是单射的。

有些偏离主题:以下是我想出的一些ASCII艺术,以帮助可视化字符的不同概念。垂直分隔的是 human abstract machine 级别。随意提出更好的名字......

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

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

  • 字节序列有效,即不包含过长序列或编码非字符码点
  • 字符序列被规范化,因此等效的字形集群具有唯一的表示

答案 2 :(得分:3)

首先你需要一些术语:

  • :(抽象概念,不是Unicode)您要表示的某些字母或符号。
  • Codepoint :与Unicode字符关联的数字。
  • Grapheme群集:一系列与单个字母对应的Unicode代码点,例如:a + ́用于字母á
  • Glyph :(字体级别的概念,而非Unicode格式):字母的图形表示。

每个代码点(例如:U + 1F4A9)获得UTF-8中字节的唯一表示形式(例如:0xF0 0x9F 0x92 0xA9)。

有些字母可以用几种不同的方式表示为代码点(即:作为不同的字形簇)。例如:á可以表示为单个代码点á(LATIN SMALL LETTER A WITH ACUTE),或者它可以表示为a(LATIN SMALL LETTER A)的代码点+ ́的代码点(COMBINING ACUTE ACCENT)。 Unicode有几种规范的规范化形式来处理这种情况(例如:NFC或规范规范化形式C是一种松散的规范化形式,具有较少的代码点,而NFD被完全分解)。

然后,还有连字(例如:)和一些其他与演示相关的字母变体(例如:上标,不间断空格,在单词的不同位置具有不同形状的字母, ...)。其中一些是Unicode格式,允许无损往返转换为遗留字符集。 Unicode具有兼容性规范化形式(NFKC和NFKD)来处理这个问题。

答案 3 :(得分:2)

是。 UTF-8只是编码Unicode字符的标准方法。这样做是为了只有一种方法来编码每个Unicode字符。

有点偏离主题:知道一些角色在外观上(与人类相似)可能是有用的,但它们仍然不同 - 例如西里尔文中有一个与'/'非常相似的符号。

答案 4 :(得分:0)

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

然而,用于对字符进行编码的方法如果不满足此要求,则可以对多个字符进行多种编码 - 虽然不合适,但在某些情况下可以完成此操作。

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