utf-8 和 unicode 之间相互转换

UNICODE 基本知识

Unicode 及编码方式概述,这篇文章写得非常详细,不明白的细节可以参考那篇文章。

UTF-8 编码

UTF-8UNICODE的实现方式之一。

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

UTF-8的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面 7 位为这个符号的 UNICODE 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的,因为首位是0,所以只能表示U+0000U+007F范围内(十进制为0 ~ 127)。
  2. 对于 n 字节的符号(n>1),第一个字节的前 n 位都设为1,第 n+1 位设为0后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 UNICODE 码。

下表总结了编码规则,字母 x 表示可用编码的位。

unicode 符号范围 utf-8 编码方式
十六进制 二进制
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

从上表可以看到:

  1. 首字节前几位可以看出这个UNICODE字符的长度,如:
    1. 110开头的则说明这个字符是2BYTEUNICODE字符;
    2. 1110开头则是3BYTEUNICODE字符;
  2. 需要注意的是单字节字符第一位上是0,而不是10
  3. 10开始的字节被用于 2 个字节长度以上的UNICODE字符的非首字节上。

所以从0101101110这些字节点的设计利用上可以看到UTF-8编码设计非常巧妙。

以汉字为例,演示如何实现UTF-8编码。

已知的 UNICODE 是4e25(100111000100101),根据上表,可以发现4e25处在第三行的范围内(0000 0800-0000 ffff),因此"严"的UTF-8编码需要三个字节,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。然后,从"严"的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,"严"的UTF-8编码是 "11100100 10111000 10100101",转换成十六进制就是e4b8a5

在 firebug 中测试中文"胡"字:

console.log(encodeURI('胡'));// "%E8%83%A1"console.log('胡'.charCodeAt().toString(16));// "80e1"console.log('胡'.charCodeAt().toString(2));// "1000000011100001"console.log(parseInt('111010001000001110100001', 2));// 15238049console.log(parseInt('111010001000001110100001', 2).toString(16));// "e883a1"

其中将1000000011100001对应位置补上110或者10,生成 unicode 二进制值111010001000001110100001,反过来从 unicode 转到 utf-8 只要移除对应位置上的11010即可得到 utf-8 的二进制值。

关于 BOM 和字节序

虽然不是标准,但许多 Windows 程序(包括 Windows 记事本)在UTF-8编码的文件的开首加入一段字节串EF BB BF。这是字节序掩码U+FEFFUTF-8编码结果。
而 POSIX 系统上明确不建议使用字节序掩码,即BOM(byte order mask),这会与bash脚本中开头的 bashbang(#!)有冲突,影响到脚本执行。

字节0xFE0xFFUTF-8编码中从未用到,同时,UTF-8以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序的问题,也因此它实际上并不需要BOM: byte-order-mark

UTF-8 Encoding Scheme

References

  1. Unicode 及编码方式概述
  2. http://yuweijun.blogspot.com/2008/06/unicode.html
  3. http://yuweijun.blogspot.com/2008/08/unicode-and-html-entities-in-javascript.html
  4. http://dreamstone.iteye.com/blog/77939
  5. UTF-8