Unicode是一个字符库,里面收录了全世界绝大多数的字符,并用0,1,2,,,n对每一个字符进行唯一的编号,这些编号我们称之为码点。
当前Unicode字符被分为17组编排,每组称为一个平面,每个平面拥有65536(即2^16)个字符。
包含最前面的65536个字符,即码点范围从0 ~ 2^16 - 1,称为基本多文种平面(Basic Multilingual Plane, BMP)。所有最常见的字符都在这个平面里面,这是Unicode最先定义和公布的一个平面。剩下的16组平面称为辅助平面。
17组平面可以包含2^(5+16)个字符,即需要21位的编码空间,比3字节略少。
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。考虑一些极端的例子: 1.用二进制代码表示Unicode中码点为1的字符,使用1个字节就是00000001;使用2个字节就是00000000 00000001;使用3个字节就是00000000 00000000 00000001;使用4个字节就是00000000 00000000 00000000 00000001。很显然如果使用四个字节存储该字符,将造成极大的空间浪费。 2.用二进制代码表示Unicode中码点为100000的字符,至少需要3个字节,即 00000001 10000110 10100000,当然也可以用4个字节00000000 00000001 10000110 10100000来表示。
考虑到系统平台的差异以及出于节省存储空间的因素,Unicode并没有对使用多少个字节来存储一个字符对应的二进制代码做出强制的规定,因此Unicode的实现方式有多种,而Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)
我们平时常见的编码方案,比如ASCII、UTF-8、UTF-16、UTF-32都是对Unicode的不同实现。 ASCII编码:使用1个字节来表示一个字符,该编码方案仅适用于对Unicode中的前128位字符,适用于西文文档。 UTF-32编码:使用4个字节表示一个字符,理论上4个字节可表示2^32 = 4,294,967,296,远超当今的Unicode所接纳的字符,因此可以完全对应Unicode编码。该编码的优点是转换规则简单直观,查找效率高,但是也有致命的缺点,浪费空间,同样内容的英语文本,它会比ASCII编码大四倍,目前基本上没有什么场景去使用这种编码方式。 UTF-8编码:在衡量一个程序设计好坏时,时间和空间这两个维度的复杂度是永远绕不开的。如果你内存足够大,你完全可以用空间换时间,但是从编码设计角度来说,人们真正需要的还是一种节省空间的编码方案,这直接导致了目前使用最多的utf-8编码方案的诞生。UTF-8是一种变长的编码方法,字符长度从1个字节到4个字节不等。越是常用的字符,字节越短,最前面的128个字符,只使用1个字节表示,与ASCII码完全相同(为了方便书写,后面涉及到的二级制代码统一用16进制表示)。
UTF-16编码:介于UTF-32与UTF-8之间,同时结合了定长和变长两种编码方法的特点。它的编码规则很简单,基本平面的字符占用2个字节,辅助平面的字符占用4个字节。也就是说,UTF-16的编码长度要么是2个字节(U+0000到U+FFFF),要么是4个字节(U+010000到U+10FFFF)。前面介绍过了基本平面包含了 65536 = 2^16 个字符,因此用两个字节去表示非常合适。
那么紧接着问题就来了,计算机怎么知道当前的这个字符,它应该读取两个字节还是四个字节呢?下面具体来说对应的解决方案。具体来说,辅助平面的字符位共有2^20(即 2^4(辅助平面个数) x 2^16(每个辅助平面理论上可容纳的字符个数))个,就是说,对应这些字符至少需要20个二进制位。UTF-16将这20位拆成两半,前10位映射在U+D800到U+DBFF(即56319 - 55296 = 2^10,空间大小2^10),称为高位(H),后10位映射在U+DC00到U+DFFF(计算同前面的高位,空间大小2^10),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。当我们遇到两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定: 1.紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间 2.这四个字节必须放在一起解读
由于历史的原因,JavaScript使用UCS-2编码,该编码方案使用2个字节表示一个字符。该编码方案对于Unicode中大于2个字节的字符处理带了很多的局限性,比如一个占用4个字节的字符,如果用使用UCS-2编码方案处理,会被处理为两个字符,这会导致字符串的长度以及使用字符相关的函数,都无法得到正确的返回结果,要想得到正确的结果,必须使用polyfill部署自己的版本。
主要参考阮一峰的博客http://www.ruanyifeng.com/blog/2014/12/unicode.html