Unicode 创造史参考 https://www.jianshu.com/p/36d20de2a1ee
Base64
Base64 是网络上最常见的用于传输 8bit 字节代码的编码方式之一。
- 有时候我们需要把二进制数据编码,然后放在URL中传输,以便不会被人直接看出。
- 通过编码防止意外生成的系统定界字符
- 编码为base64之前 数据是以字节数组存放, 里面任何二进制字符都是可能的。如果有的语言以\0作为字符串结束标志,正好字节数组里面有\0的话,可能会有问题。
简单来讲,Base64就是用下列总计64个字符去表示二进制数据的:
- A-Z
- a-z
- 0-9
- +
- /
编码规则:
- 把三个字符变成四个字符
- 没76个字符加一个换行符
- 最后的结束符也要处理
Base64字符串的长度必然是4的整数倍。由于二进制的字节数不一定是3的整数倍,所以Base64字符串在结尾是可能有空的。这些空的状态,Base64引入第65个字符 “=” 去表示:
对于base64编码,常常在网络中用于编码长标识符。编码规则是每3个8位字节为一组,分成4组6位字节,并且每个字节的高位补零,形成4个8位的字节。base64编码具有可逆性。
w3c浏览器内置了window.btoa()
和 window.atob()
来完成二进制数据或者ASCII字符到base64的转换(注意:该方法只能用于ASCII码成Base64,不适用中文等)
- atob则是ascii to binary,用于将ascii码解析成binary数据,即Base64的解码过程
- btoa是binary to ascii,用于将binary的数据用ascii码表示,即Base64的编码过程
"ABC" 按照 Base64编码 为 "QUJD"
"中国" 按照 Base64编码 为 "JXU0RTJEJXU1NkZE"
8421 BCD
bcd码用来打印二进制。把任意一个字符变成2个可见的十六进制字符(0-9a-z 或 0-9A-z)。
相比于Base64的隐蔽性,BCD码的优势在于其可读性好。
URL
对于uri的编解码,在js中有3对函数,分别是escape/unescape
, encodeURI/decodeURI
, encodeURIComponent/decodeURIComponent
。
它们的适用范围不同,而且遵循的编码规范也不同。
相同点:
对于上述函数而言,所有的ASCII的字符编码相同,采用%XX的形式。
不同点:
- 而对于unicode字符,escape编码形式为%uXXXX
- 而其余两个函数则先将unicode字符按照utf-8对其进行编码,然后继续进行uri编码(百分号)。对于中文字符,每个字符用urf-8编码则为3个字节,然后在每个字节前面加上%即可。
三个函数对应的安全字符
- escape(69个):*/@±._0-9a-zA-Z
- encodeURI(82个):!#$&’()*+,/:;=?@-._~0-9a-zA-Z
- encodeURIComponent(71个):!’()*-._~0-9a-zA-Z
encodeURIComponent(s) = escape(unicodeToUTF8(s));
unicodeToUTF8(s) = unescape(encodeURIComponent(s));
ASCII
在计算机发明的时候 ,由于计算机你只能表示二进制的数据,美帝人民为了交流通信方便,约定了一个编码系统,就是ASCII码,把abc…xyz…ABC…XYZ…!@#…等字符分别和0,1,2,3,4…对应,发现差不多刚好128个数,半个字节的长度,为了防止以后需要为新的符号编码,于是干脆取一个字节,最高位置为0。后七位从0-127分别对每一个符号编码。
ISO
后来欧洲人也玩计算机,发现不行啊,还有很多符号(法语,德语)ASCII没办法表示啊,于是欧洲人自己也撸了一套编码,一个字节的长度,把最高位也用掉了。这套编码叫ISO。
GBK
中国人不高兴了,特么我们汉字有几万个,常用的就有几千个,没有两个字节根本交不了货。于是勤劳勇敢的中国人民就破天荒的用了两个字节来表示中文。整出一套GBK。为了现实我中华民族兼容并蓄,我们兼容了ASCII编码。
gbk编码规定,计算机不能在每次都只读一个字节那么死板了,你要先看看第一位是不是为0,要是为0 的话,就当作ASCII码来读入一个字节,不然的话就读入两个字节。
Unicode
Unicode 是容纳世界所有文字符号的国际标准编码,使用四个字节为每个字符编码。
function toUnicode(data) {
if(data == '' || typeof data == 'undefined') return '';
let str = '';
for(let i=0; i < data.length; i++) {
let tmp = data.charCodeAt(i).toString(16);
//由于Unicode固定使用四个字节为每个字符编码,因此如果没达到就要补全
while(tmp.length < 4) {
tmp = "0" + tmp;
}
str += "\\u" + tmp;
};
return str;
}
function formUnicode(data) {
if(data == '' || typeof data == 'undefined') return '';
return unescape(data.replace(/\\u/g, "%u"));
//return eval("'" + data + "'").toString();
}
"ABC" 按照 Unicode编码 为 "\u0041\u0042\u0043"
"中国" 按照 Unicode编码 为 "\u4e2d\u56fd"
UTF-8
但是如果类似于1号编码这样的小数据编号也要三个字节的话,那么也就是0x000001,这简直就是浪费啊,明明一个字节就可以表示了,你非得整三个。于是就出现了uft-8,utf-16,utf-32这些编码方案。
utf-8为了节省资源,采用变长编码,编码长度从1个字节到6个字节不等
- 如果开头是0,表示只有1个字节;
- 否则,头一个字节的第一个0前面多少个1就表示有多少个字节
- 第二个字节起,每个字节都用 10 打头
- 第二个字节比第一个多了 4 比特(共11比特),其后每多一个字节,增加 5 比特
- 从第二位开始,除了标志位,还有一部分数值未利用(少一个字节可以表示的最大值)
utf-8最小是1字节,utf-16最小是2字节,utf-32最小是4字节。所以英文在utf-16中也是2个字节,而在utf-8中则是1个字节。在当大部分是英文的时候utf-8更加节省资源。如果在我们在中文世界里来比较他们,则是utf-16更加节省资源。
"ABC" 按照 urf-8编码 为 "0x410x420x43"
"中国" 按照 urf-8编码 为 "0xE40xB80xAD0xE50x9B0xBD"
function toUtf8(data) {
if(data == '' || typeof data == 'undefined') return '';
let str = '';
data = unescape(encodeURIComponent(data));
for(let i=0; i < data.length; i++) {
let tmp = data.charCodeAt(i).toString(16).toUpperCase();
while(tmp.length < 2) {
tmp = "0" + tmp;
}
str += "0x" + tmp;
};
return str;
}
function fromUtf8(data) {
if(data == '' || typeof data == 'undefined') return '';
let str = '';
data.replace(/0x(\w{2})/g, function(){
str += String.fromCharCode(parseInt(arguments[1], 16));
});
return decodeURIComponent(escape(str));
}