Unicode和UTF-8字符编码

概念

  • Unicode: (Universal Code 统一码)是一个囊括了世界上所有字符的字符集,其中每一个字符都对应有唯一的编码值(code point),然而它并不是一种什么编码格式,仅仅是字符集而已

    Unicode 字符不管具体怎么编码和存储,可以用 UTF-8UTF-16来编码

    UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因

  • UTF-8: (Unicode Transformation Format)就是在互联网上使用最广的一种Unicode的实现方式(怎么编码,怎么存储)。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32 (字符用四个字节表示)

    UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度

1
UTF-8 and Unicode cannot be compared. UTF-8 is an encoding used to translate numbers into binary data. Unicode is a character set used to translate characters into numbers.

UTF-8编码

字符UnicodeUTF-8GBK
01001110 00101101(4e2d)01001110 00101101(e4b8ad)11010110 11010000(d6d0)

UTF-8常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4个字节.如果要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:

1
2
3
4
5
6
7
8
9
10
>>> a = u"中"
>>> a
u'\u4e2d'
>>> b = a.encode("utf-8")
>>> b
'\xe4\xb8\xad'
>>> c = a.encode("gbk")
>>> c
'\xd6\xd0'
>>>

「中」用 GBK 编码转后就是用2个字节表示,用 UTF-8 编码就是 3 个字节,同一个字符用不同的编码方式占用的字节长度可能不一。

编码规则

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

1
2
3
4
5
6
7
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 ~ 007F | 0xxxxxxx
0080 ~ 07FF | 110xxxxx 10xxxxxx
0800 ~ FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1 0000 ~1F FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

BOM

BOM:在一个文本文件或者一段字符编码前加上几个固定的字节用于识别,这些字节保证不对应任何一个字符,所以软件一读就能验明正身:

  • EF BB BFUTF-8
  • FF FEUTF-16LE(Little endian)
  • FE FFUTF-16BE(Big endian)

以汉字「中」为例,Unicode码是4e2d,需要用两个字节存储,一个字节是4e,另一个字节是2d。存储的时候,4e在前,2d在后,就是Big endian(高位字节在前,阅读顺序)方式;2d在前,4e在后,就是Little endian(低位字节在前)方式。Windows的记事本还有Windows其它地方所谓的Unicode编码,其实是UTF-16LE

其他编码

ISO-8859-1

ISO-8859-1仍然是单字节编码,它总共能表示 256 个字符。

GB2312

全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK

为了扩展GB2312,加入更多的汉字,它的编码范围是8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。

参考

https://stackoverflow.com/questions/3951722/whats-the-difference-between-unicode-and-utf-8

字符编码笔记:ASCII,Unicode和UTF-8

常识性错误之 Unicode 与 UTF-8

热评文章