乐趣区

前端培训中级阶段16-Unicode和UTF编码20190912期

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。

编码解码对于 web 开发来说,有可能最常见的是URL 编码(encode decode)。

ASCII 编码

计算机处理的内容是二进制 ,对应开和关的状态。如果要处理文本,也是把文本转换为数字然后做比对。最早的计算机在设计时采用 8 个比特(bit)作为一个字节(byte)
一个字节能表示的最大的整数就是 2550b11111111==255)。这 255 个数字被用来表示大小写英文字母、数字和一些符号,这个 编码表被称为 ASCII 编码,比如大写字母 A 的编码是 65,小写字母 a 的编码是 97。

ASCII 对照表

GB2312 编码

如果要表示中文,显然 ASCII 的一个字节是不够的,至少需要两个字节,而且还不能和 ASCII 编码冲突。
所以,中国制定了 GB2312 编码(国标 2312 编码),用来把中文编进去。

Unicode 编码

Unicode(万国码),包括字符集、编码方案等。
Unicode 是为了解决传统的字符编码方案的局限而产生的,它 为每种语言中的每个字符设定了统一并且唯一的二进制编码 ,以满足 跨语言 跨平台 进行文本转换、处理的要求。1990 年开始研发,1994 年正式公布。
Unicode通常用 两个字节表示一个字符 原有的英文编码从单字节变成双字节 ,只需要把 高字节全部填为 0 就可以。目前的 Unicode 字符集为 0x00000x10FFFF,分为17 组编排,,每平面拥有65536 个码位,共1114112 个码位

Unicode 到目前为止所定义的十七个平面中,第 0 平面 (BMP) 最为重要。

中文范围 4E00-9FA5:CJK 统一表意符号 (CJK Unified Ideographs)

Unicode 中:“李”字对应的数字是26446(十进制),十六进制表示为0x674e

UTF 编码系列

Unicode 只是一个大的合集,UTF-8UTF-16UTF-32才是将数字转换到程序数据的编码方案。
UTFUnicode Transformation Format 的缩写,可以翻译成Unicode 字符集转换格式,即怎样将 Unicode 定义的数字转换成程序数据。

UTF-8

UTF- 8 的 特点是对不同范围的字符使用不同长度的编码,这点极大的缩小了文件的大小。当然,也会造成一定的性能浪费,

对于 0x00-0x7F 之间的字符,UTF- 8 编码与 ASCII 编码完全相同。
对于超过区间的字符,最高位非 0,10标识当前属于前面字节的描述字节。110标明这是两个字节的,后面还会跟着一个字节。

UTF- 8 编码的最大长度是 4 个字节。从表格中可以看到,4 字节模板有 21 个 x,即可以容纳 21 位二进制数字。Unicode 的最大码位 0x10FFFF 也只有 21 位。

Unicode 编码(十六进制) UTF-8 字节流(二进制)
000000-00007F 0xxxxxxx
000080-0007FF 110xxxxx 10xxxxxx
000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
“李”\u674e 11100110 10011101 10001110
“A”\u0041 01000001

UTF-16

UTF-16 编码以 16 位无符号整数为单位 。我们把 Unicode 编码记作 U。
如果 U<0x10000,UTF-16 编码(二进制)就是对应的 16 位无符号整数。
如果U≥0x10000,先计算U'=U-0x10000,然后将 U ’ 写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U 的 UTF-16 编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx

这里,你会好奇,因为第二条规则会和第一条规则重复。为了将编码区分开来,Unicode编码的设计者将 0xD800-0xDFFF 保留下来,并称为 代理区(Surrogate)

// D800-DB7F    High Surrogates    高位替代
// 指 UTF-16 编码中。两个位置中的第一个位置
(0xD800).toString(2) == 1101100000000000
(0xDB7F).toString(2) == 1101101101111111

// DC00-DFFF    Low Surrogates     低位替代
// 指 UTF-16 编码中。两个位置中的第二个位置
(0xDC00).toString(2) == "1101110000000000"
(0xDFFF).toString(2) == "1101111111111111"

// DB80-DBFF    High Private Use Surrogates      高位专用替代
(0xDB80).toString(2) == "1101101110000000"
(0xDBFF).toString(2) == "1101101111111111"

UTF-32

UTF-32 编码以 32 位无符号整数为单位。Unicode 的 UTF-32 编码就是其对应的 32 位无符号整数。

字节序

字节序有两种,分别是“大端”(Big Endian, BE)和“小端”(Little Endian, LE)。
根据字节序的不同,UTF-16 可被实现为 UTF-16LE 或 UTF-16BE,UTF-32 可被实现为 UTF-32LE 或 UTF-32BE。

Unicode 编码 UTF-16LE UTF-16BE UTF32-LE UTF32-BE
0x006C49 49 6C 6C 49 49 6C 00 00 00 00 6C 49
0x020C30 43 D8 30 DC D8 43 DC 30 30 0C 02 00 00 02 0C 30

Unicode标准建议用 BOM(Byte Order Mark) 来区分字节序,即在传输字节流前,先传输被作为 BOM 的字符“零宽无中断空格”。这个字符的编码是 FEFF,而反过来的 FFFE(UTF-16)和 FFFE0000(UTF-32)在 Unicode 中都是未定义的码位,不应该出现在实际传输中。

UTF 编码 Byte Order Mark (BOM)
UTF-8 without BOM
UTF-8 with BOM EF BB BF
UTF-16LE FF FE
UTF-16BE FE FF
UTF-32LE FF FE 00 00
UTF-32BE 00 00 FE FF

URL 编码 / 解码

url 编码是一种 浏览器用来打包表单输入的格式
浏览器将表单中获取到的内容,以 name=value 参数编码,作为 URL 的一部分或者放入 body 发给服务器。转换成如:a=1&b=2

基于上面的规则,=或者 & 都会造成解析异常。所以特殊的字符(不是简单的七位 ASCII,如汉字,关键词),会以 %XX 这个格式转义,比如:

字符 encode 编码 utf- 8 编码
= %3D 00111101
%E6%9D%8E 11100110 10011101 10001110
// 转换代码
encodeURIComponent('李').replace(/%([0-9a-f]{2})/gi, (v,group1)=>parseInt(group1,16).toString(2)+'') //"11100110 10011101 10001110 "encodeURIComponent('=').replace(/%([0-9a-f]{2})/gi, (v,group1)=>parseInt(group1,16).toString(2).padStart(8,'0')+' ') //"00111101 "

微信公众号:前端 linong

参考文献

  1. 前端培训目录、前端培训规划、前端培训计划
退出移动版