JavaScript 进阶营前端开发笔记

字符编码

2018-08-14  本文已影响2人  weiee

1. 预备知识

  1. 码位:code point / position,组成代码页的数值。例如:ASCII码包含128个码位,范围是0到7F。

  2. 码元:code unit,指一个已编码的文本中具有最短的 位(bit)组合 的单元。例如:UTF-16的码元是16bit长。

  3. UTF-16:是Unicode字符编码表的一种实现方式。即把Unicode字符集的抽象 码位 映射为16bit长的整数(码元)的序列。Unicode的码位需要1~2个16bit长的码元表示。

  4. 代理对(surrogate pair):超出1个16位码元表示范围的码位(辅助平面的码位)需要2个码元表示,则称组成该码位的两个码元组合为 代理对 ,分别为前导代理(high-surrogate)码元和后尾代理(low-surrogate)码元。

  5. Unicode:与ISO(通用字符集)类似的字符集。对世界上大部分的文字系统进行了整理、编码,使得计算机可以用更为简单的方式来呈现和处理文字。

    • Unicode编码范围从U+0000到U+10FFFF,共计2^20个,采用两个16位长的整数组成。
    • Unicode编码分为17个平面(plane),每个平面包含65536个码位。
    • 每个平面的码位可表示为U+xx0000 ~ U+xxFFFF。
    • 第一个平面为基本多语言平面(Basic Multilingual Plane, BMP),或第零平面。
    • BMP内,从U+D800~U+DFFF(8 x 16^2共计2048个值)之间的码位是永久保留不映射到Unicode字符。
    • 代理对的高位代理表示前10位+0xD800,低位代理表示后10位+0xDC00。
  6. 组合字符:组合字符是由两个码位组成的字符,由基础字符结合特殊字符组成。注意组合字符并不是1个代理对,而是由两个码位组成。例:
    console.log('\u0061'); // => 'a'console.log('\u030A'); // => "̊ "
    console.log('\u0061\u030A'); // => 'å'

2. JavaScript中的Unicode

String定义:String类型是由0个或多个16位无符号整型值(元素)组成的有序序列,最大长度为2^53-1个元素。String的每个元素被当做一个UTF-16的码元。

如果字符串中含有代理对或者组合字符,则一些字符串操作会带来困扰:

2.1 字符串比较:

一些带有语调符号的字符Unicode提供两种表示方式,一种直接提供对应的码位(不一定是代理对,也有可能在BMP平面),一种提供组合字符(即原字符与语调符号的组合)。因此,字符串的渲染结果并不能明确地反应它的码元,相同渲染结果的字符串长度也可能不同。

2.2 字符串长度:

string的length属性只是字符串的码元个数,如果字符串中含有代理对或组合字符,则length属性的值会比预期的字符串长度大。

2.3 字符定位:

字符串是码元序列,通过字符串索引定位双码元字符有困难。

2.4 正则匹配:

正则表达式与字符串一样,也是基于码元的。因此,使用正则表达式在处理代理对和组合字符序列时也会遇到困难。

var regex = /[😀-😎]/; 
// Uncaught SyntaxError: Invalid regular expression: /[😀-😎]/: Range out of order in character class at <anonymous>:1:13

示例中的正则表达式表示匹配字符😀与字符😎范围之间的字符,然而辅助平面字符用代理对表示,因此regex被js表示为/[\uD83D\uDE00-\uD83D\uDE0E]/。然而在正则表达式中,每个码元被当做一个单独的元素,代理对被忽略。\uDE00大于\uD83D\uDE00-\uD83D这个字符区间是无效的。

解决方法:使用正则表达式u标识。
在正则表达式中可以使用Unicode转义序列/u{1F600}/u

var x = "\uD83D\uDE00"  // x = 😀
var regex = /\u{1F600}/u;
regex.test(x) // true

注意:不论有没有u标志,正则表达式都会把组合字符视为独立的码元来处理。

2.5 JS转义序列:
  1. 16进制转义序列:是最短的转义序列,\x<hex>,<hex>是一个2位的16进制数。
  2. Unicode转义序列:可表示整个BMP的码位,两个连续的Unicode转义序列也可表示代理对组成的辅助平面的码位,\u<hex>,<hex>是一个4位的16进制数。
  3. 码位转义序列:ES6新提供的代表整个Unicode空间的码位,即BMP和辅助平面。表示方法:\u{<hex>},<hex>是1~6位的16进制数。可替代Unicode转义的代理对使用。
  4. 8进制转义序列:<8进制>,ES v3不支持,谨慎使用。

参考文章

  1. 每个JavaScript开发者都该懂的Unicode
  2. What every JavaScript developer should know about Unicode
  3. ES6关于Unicode的相关扩展
上一篇下一篇

猜你喜欢

热点阅读