为什么添加UTF-8编码的两个字节不能给出字符的代码点?

时间:2017-04-05 11:36:37

标签: unicode encoding utf-8

首先,我对UTF-8编码方案如何工作的理解可能是错的,因为我刚刚开始使用unicode。我遇到一个有趣的webpage说:

  

但是,Unicode字符的编码方案与ASCII兼容。它被称为UTF-8。在UTF-8下,0到127之间字符编号的字节编码是单字节的二进制值,就像ASCII一样。但是,对于128到65535之间的字符数,使用多个字节。如果第一个字节的值介于128和255之间,则会将其解释为指示要遵循的字节数。后面的字节编码单个字符编号。字符编码后面的所有字节也都有128到255之间的值,因此0到127之间的单字节字符和多字节字符表示的字节之间永远不会有任何混淆。

     

例如,拉丁语1和Unicode中字符编号为233的字符é由传统Latin 1编码中的值为233的单个字节表示,但表示为两个字节,值为195和UTF-8中的169。

在我的解释和理解中,因为字符é在unicode(233)中的值大于128,所以它由两个字节表示。这两个字节的值介于128和255之间,以区分仅需要一个字节的ASCII字符,技术上使用7位。 B ut如何使用存储在两个字节中的值195和169来达到数字233?或者从两个字节中获取233的过程是什么?显然,如果我们添加两个值(两个字节),我们得到 195 + 169 = 364 ,这与字符的代码点é,233。我在这里缺少什么?

*我完全理解一些字符需要更多字节来表示,但这是另一个故事。

1 个答案:

答案 0 :(得分:6)

UTF-8是一种编码方案。仅将原始字节添加到一起是不够的,您必须首先删除编码部分,然后将剩余的位连接(不添加)。

UTF-8在RFC 3629中正式定义,它定义了下表:

Char. number range  |        UTF-8 octet sequence
   (hexadecimal)    |              (binary)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Wikipedia上可以更好地看到这一点:

UTF-8 encoding

现在,让我们将它应用于您的示例Unicode字符é,即Unicode代码点U+00E9 SMALL LETTER E WITH ACUTE

如果查看该表,则代码点U+00E9属于第二行,因此使用两个字节进行编码:

110xxxxx 10xxxxxx

10是文字的,它们必须如编码字节所示。 x代表正在编码的代码点的原始位。

将最高位设置为1可确保字节不会与7位ASCII字符混淆。编码序列的第一个字节中的1个数也用于指定完整序列中总字节数。

完整的Unicode指令表最多需要21位来表示所有可能的代码点(最多包括U+10FFFF,这是UTF-16可以物理编码的最高代码点.UTF-8可以物理编码更高的代码点,但由RFC人为限制,以保持与UTF-16的100%兼容性。由于大多数编程语言中没有21位数据类型,因此下一个最高数据类型是32位整数。

代码点U+00E90x000000E9,为十六进制的32位数字。那是二进制位00000000 0000000 00000000 11101001。表的第2行仅使用代码点的11位,因此您将剥离高21位并用剩余的11位低位填充x

   11000000 10000000
OR    00011   101001
--------------------
   11000011 10101001 = 0xC3 0xA9

要反转该过程,只需从每个字节中删除非x位,并将其余位加在一起:

    11000011 10101001
AND 00011111 00111111
---------------------
       00011   101001 = 11101001 = 0xE9

如果您需要帮助在特定的编程语言中实现此算法,那么有很多示例和教程可以从编码角度展示算法。