在上一篇我们讲解了?Unicode 和 UTF-8 的关系,今天,让我们来看看在 JavaScript 中 编码格式的应用。
Unicode 就是包含了所有的字符在一个集合内,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了。Unicode 中的每一个字符都指定了一个编码,称为符号的“码点”。
U+0000? ?
U+ 紧跟在后面的十六进制数就是 Unicode 码点。
?现如今 Unicode 14.0 是?Unicode 标准的计划版本,以跟随 Unicode 13.0.Unicode 多达十多万个字符,这么多的字符不是一次性定义的,而是分区定义。每个区可以存放65536个(2^16)字符,称为一个平面(plane)。目前,一共有17个(2^5)平面,也就是说,整个Unicode字符集的大小现在是2^21。
最前面的65536个字符位,称为基本平面(缩写BMP),?它的码点范围是从0一直到216-1,写成16进制就是从U+0000到U+FFFF。它是Unicode 最先定义和公布的一个平面。剩下的字符都放在辅助平面(简称 SMP ),码点范围从 U+010000 到 U+10FFFF。
UTF-16 是介于 UTF-32 和 UTF-8的, UTF-32 的每个码点是使用四个字节,字节内容一一对应码点。UTF-8 是可变长的使用 1-4个字节不等。而UTF-16 是使用二个字节(U+0000到U+FFFF)和四个字节(U+010000到U+10FFFF)。
正常写的话,我们一个码点占两个字符,那么我们是把 遇到的两个字节看作一个字符,还是与后面的两个字节一起看作一个字符呢?我们得有一个识别的依据吧,UTF-8 会把一个字节的第一位是0还是1来进行不同的表示字节占有数。
UTF-16 是怎么表示的呢? 还记得前面说的平面嘛,在基本平面内,从 U+D800 到 U+DFFFF, 是一个空段,这些个码点不对应字符,感觉是故意这么设计的,反正非常的巧妙,我们可以利用这些空的码点进行一个映射,因为?辅助平面的字符位共有 2^20 个,而且空出来的正好是 2^20 个空白的码点,我们可以非常巧妙的利用到这空出的码点。将这20位拆成两半,前10位映射在U+D800到U+DBFF(空间大小2^10),称为高位(H),后10位映射在U+DC00到U+DFFF(空间大小210),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
所以,当我们遇到两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。
我们怎么来进行 UTF-16 的转码呢?
首先,给定一个 Unicode 的码点,我们需要确定,它是属于基本平面的字符,还是在辅助平面的字符,如果是前面的字符,直接将码点转为对应的十六进制形式,长度为两个字节。
U+597D = 0x597D
如果是辅助平面的,我们就需要先映射,然后在转十六进制。
我们可以以中文中的 “汉” 为例, Unicode 的码点为?0x20BB7,很明显超出了基本平面的范围 (0x0000-0xFFFF),因此需要使用四个字节表示。那么如何转为 UTF-16呢?
首先得计算出来,它的超出的部分。?
0x20BB7 - 0x10000 计算超出的部分。
它是属于辅助平面的,所以是在 2^20内,所以我们用20个二进制来表示它。
结果为?0001000010 1110110111
分成两部分,前10位映射U+D800 - U+DBFF 之间.
U+D800 ?对应的二进制数为??1101100000000000,我们直接填充后面的 10 个 2进制即可。我们用 ?0001000010 来填充?1101100000000000 的 后十位. 得到?1101100001000010,转为16进制得到?0xD842.
低位的话,我们用同样的道理,得到?0xDFB7。因此得出汉子 的 UTF-16 编码为?0xD842 0xDFB7。
如果是辅助平面字符, Unicode 3.0 版本给出了转码公式
H = Math.floor((c - 0x10000) / 0x400) + 0xD800
L = (c - 0x10000) % 0x400 + 0xDcC00
那么JavaScript 中使用的是哪种编码。
在 ES 5.1 中有一段话。
A conforming implementation of this International standard shall interpret characters in conformance with the Unicode Standard, Version 3.0 or later and ISO/IEC 10646-1 with either UCS-2 or UTF-16 as the adopted encoding form, implementation level 3. If the adopted ISO/IEC 10646-1 subset is not otherwise specified, it is presumed to be the BMP subset, collection 300. If the adopted encoding form is not otherwise specified, it is presumed to be the UTF-16 encoding form.
说明了 javaScript 引擎使用的编码格式。JS 引擎可以选择使用 UCS-2 或者 UTF-16。
那么为什么会选择 UTF-8呢??由于历史原因,最先出现的 UCS-2,接着 1996 年 UTF-16 随着 Unicode 2.0 标准诞生,就可以迁移到了 UTF-16。但是它们无法移至 UTF-8,是因为这将破坏 API 接口中的二进制兼容性(以及其他功能)。
|