前端培训-中级阶段(16)- Unicode和UTF编码(2019-09-12期)

linong

前端最基础的就是 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

clipboard.png

参考文献

  1. 前端培训目录、前端培训规划、前端培训计划
阅读 1.7k

javascript-lNong
只此一生,何必从众

Read-Search-Ask

22.8k 声望
4.8k 粉丝
0 条评论

Read-Search-Ask

22.8k 声望
4.8k 粉丝
文章目录
宣传栏