编码与解码
# 编码与解码
参考教程:阮一峰-字符编码笔记:ASCII,Unicode 和 UTF-8 (opens new window)、前端数据操作总结 (opens new window)
[TOC]
# 一、字符编码
1B(byte,字节)= 8 bit
# 1.1 ASCII码
ASCII码共规定了128个字符,由7位二进制表示即可。英语用128个字符编码就够了,一个ASCII码就是1B。
'A'.charCodeAt(0) // 65
String.fromCharCode(65) // A
2
# 1.2 Unicode
Unicode是一个符号集,可容纳100多万个符号,支持多语言环境。
charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。字符串中第一个字符的位置为 0, 第二个字符位置为 1,以此类推。
'中'.charCodeAt(0)// 20013
对于英文字母,UTF-8 编码和 ASCII 码是相同的。
# 1.2.1 UTF-8
在互联网上使用最广的一种 Unicode 的实现方式。
最大特点:可变长的编码方式。可使用1-4个字节表示一个符号,根据不同的符号而变化字节长度,可避免因过多的存储浪费导致文件大小变大。
编码规则
- 于单字节的符号,字节的第一位设为
0
,后面7位为这个符号的 Unicode 码。 - 对于
n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
- 于单字节的符号,字节的第一位设为
Web要求URL的查询字符串采用UTF-8编码,对于一些特殊字符或者中文等,会编码成多个字节,变成%加相应16进制码的形式。比如:汉字 中 将会被编码为%E4%B8%AD。为此JS提供了encodeURIComponent与decodeURIComponent方法。
encodeURIComponent('中') // "%E4%B8%AD"
故可借此来实现UTF-8的编码与解码。
编码:
function encodeUtf8(text) {
const code = encodeURIComponent(text);
const bytes = [];
for (var i = 0; i < code.length; i++) {
const c = code.charAt(i);
if (c === '%') {
const hex = code.charAt(i + 1) + code.charAt(i + 2);
const hexVal = parseInt(hex, 16);
bytes.push(hexVal);
i += 2;
} else bytes.push(c.charCodeAt(0));
}
return bytes;
}
encodeUtf8('中') // [228, 184, 173]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
解码:
function decodeUtf8(bytes) {
var encoded = "";
for (var i = 0; i < bytes.length; i++) {
encoded += '%' + bytes[i].toString(16);
}
return decodeURIComponent(encoded);
}
decodeUtf8([228, 184, 173]) // '中'
2
3
4
5
6
7
8
9
# 1.2.2 UTF-16、UTF-32
基本不用。UTF-16的字符用两个字节或四个字节表示,UTF-32的字符用四个字节表示。
# 1.3 GB类
中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312是简体中文常见的编码方式,使用两个字节表示一个汉字,所以最多可以表示2的16次方65536个符号。
GB2312基本满足了计算机处理简体汉字的需求,所收录的汉字覆盖了99.75%的使用频率,但对于罕见字和繁体字,GB2312就不能处理了。因此发明了后来的GBK和GB18030。
GB18030 > GBK > GB2312
计算机操作系统中的编码:
- Windows下中文的默认编码是GBK(GB2312)
- Linux下中文的默认编码是UTF-8
# 二、URI编码与解码
# 2.1 encodeURIComponent()
编码
对统一资源标识符(URI)的组成部分进行编码的方法。它使用一到四个转义序列来表示字符串中的每个字符的UTF-8编码(只有由两个Unicode代理区字符组成的字符才用四个转义字符编码)。
不转义的字符
A-Z a-z 0-9 - _ . ! ~ * ' ( )
保留字符会转成
%XX
形式(#
不是保留字符)encodeURIComponent(';,/?:@&=+$#') // "%3B%2C%2F%3F%3A%40%26%3D%2B%24%23"
1
# 2.2 decodeURIComponent()
解码
用于解码由
encodeURIComponent
(opens new window) 方法或者其它类似方法编码的部分统一资源标识符(URI)。
当该方法使用不当时,将会抛出一个URIError
(opens new window)(“格式错误的URI序列”)异常。
encodeURI、decodeURI与上两者的区别在于,不会对任何保留字符和#进行编码处理。
# 三、Base64的编码与解码
参考教程:Base64的原理、实现及应用 (opens new window)、JS的Base64编码解码 (opens new window)
Base64编码是基于64个字符A-Z,a-z,0-9,+,/的编码方式,因为2的6次方正好为64,所以就用6bit(六位二进制)就可以表示出64个字符,用来将二进制数据转成文本数据,可确保内容在各个网关间无措传输。
# 2.1 Base64编码
btoa()
:从一个字符串或者二进制数据编码一个Base64字符串。(反着记,a-to-base64)- 仅支持ASCII,
btoa('中')
会报错。对此,可以对整个字符串进行转义(如使用encodeURIComponent
进行UTF-8转义)然后再btoa
编码。
- 仅支持ASCII,
- 标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的保留字符和
#
变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
综上所述,字符串转Base64字符串如下:
function encode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
// match是匹配的字符,p1是([0-9A-F]{2})
function toSolidBytes(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
2
3
4
5
6
7
# 2.2 Base64解码
atob()
:解码一个Base64字符串。
function decode(str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
2
3
4
5
# 三、ArrayBuffer
应用场景:canvas 图像处理、WebGL 与显卡通信、文件操作、Ajax响应。
# 3.1 ArrayBuffer转string
let uint8Array = new Uint8Array(arrayBuffer)
let stringData = String.fromCharCode.apply(null, uint8Array)
let postedString = decodeURIComponent(escape(stringData)) // 可避免中文乱码
2
3