1. 字符集和编码的关系
字符集是字符的集合,编码则是字符集中的字符要如何存储的规则。
![](https://img.haomeiwen.com/i134602/75299af5c4277d53.png)
如上图,当字符集和编码一一对应时,可能不用特意去区分;当字符集和编码一对多时,要指明编码方式就必须用准确的名称。
2. Unicode的码点
Unicode将全世界所有的符号都包含在其中,它的符号分别定义在不同的17个平面中,每个平面包含65536个(2^16)字符。
第一个平面称为基本平面,剩下的平面成为辅助平面。
![](https://img.haomeiwen.com/i134602/9969bd164507de41.png)
参考上图的编号规则,可以看到
- Unicode的码点用十六进制表示,长度在4-6位之间,少于4位实际有效前面会用0填充
- 4位十六进制等同于2字节:16^4 = (2^4)^4 =2^16=16bit
3. Unicode的编码方式
Unicode的编码方式有多种:
- UTC-32用4个字节表示一个字符,缺点是浪费空间
- UTC-8用1-4个字节表示一个字符,是常见的网页编码
- UTC-16用2或4个字节表示一个字符,结合定长和变长编码方法的特点
因为JavaScipt的编码UCS-2会跟UTC-16有一定的关系,这里作为拓展介绍一下UTC-16是如何确定一个字符是用2个字节还是4个字节表示。
(1)基本平面的字符用2字节表示(即4位16进制),直接转成对应的十六进制即为UTF-16的表示;
(2)辅助平面的字符码点范围在 U+010000~U+10FFFF之间,要把码点拆分到4个字节中就会面临一个问题,你怎么判定你拆分出来的2子节的单元是独立的还是和后续单元一起。
在基本平面内,有一个区间是不设置具体含义的,这个区间的大小为 2(2^10), 我们把辅助平面的字符一半放在前2个字节,一半放在后2个字节,各自大小为2^10长度,那么得到的总长度就是 2^20 = (2^16)16 = 辅助平面大小*16
![](https://img.haomeiwen.com/i134602/2930c98d0bda321a.png)
看到如果有编码是在 D800-DFFF之间,基本就可以判定是辅助平面的字符。
4. JavaScript的编码UCS-2
Javascript使用的编码非上面的任何一种,而是用的UCS-2的编码,它采用两个字节存储一个字符。
UCS团队早期和Unicode团队一样,都是为了建立一个涵盖所有字符的字符集。UCS-2是支持UCS字符集的编码方式。
JavaScript语言采用了UCS-2作为自己的编码方式,那时候只有一个基本平面,2个字节就够用了。
而后才有了UCS和Unicode两家成员决定合并保留Unicode一个字符集,进一步发展出UTC-16的故事。
UTC-16明确宣布是UCS-2的超级,即基本平面跟UCS-2一样,辅助平面用于4个字节的表示。
因为JavaScript只能处理UCS-2编码,4个字节的字符,会当做两个双字节字符来处理,因此所有字符串的函数都无法正确返回结果。
5. 编码相关实用方法
5.1 字符和字节的关系
Javascript使用UCS-2编码,一个字符用两个字节表示:1字符 = 2字节
5.2 字符串的长度
基本平面的字符长度为1,辅助平面的字符长度为2,因此视觉长度为n的字符串,实际使用 length 属性获得的长度可能在 n-2n之间。
5.3 字符编码的查看
可以使用 String.prototype.chartCodeAt(index)
加 toString(16)
来查看字符的十进制编码:
'a'.charCodeAt(0).toString(16) // 61
5.4 四字节字符的遍历
一个四个字节表示的字符,可以使用数组下标 或 for...in
循环遍历到两个双字节,每一个只是字符的一部分,输出是无正常展示的;而ES6提供的 for...of
可以自动识别四字节的编码。
var s = '𝌆';
for(var i in s){
console.log(s[i])
//�
//�
}
for(var i of s){
console.log(s[i])
//𝌆
}
5.5 码点表示法
如下的表达式是成立的,其中第三是ES6为了识别4字节字符所处的修复,加上{}
才能正常识别
'\u0061' === 'a'
// 使用两个双字节表示一个辅助平面字符
'\ud834\udf06' === '𝌆'
//ES6新增的码点表示法
'\u{1d306}' === '𝌆'
5.6 其他方法
- String.fromCodePoint():从Unicode码点返回对应字符,参数为十进制十六进制皆可
- String.prototype.codePointAt():从字符返回对应的码点,
'𝌆'.codePointAt(0)
的输出即为1d306
- String.prototype.at():返回字符串给定位置的字符,自己浏览器尝试了一把暂时不支持
- 正则表达:ES6提供了u修饰符,对正则表达式添加4字节码点的支持。
/^.$/u.test('𝌆') // true
/^.$/.test('𝌆') // false
网友评论