ES6有关Unicode的相干扩展

前面的话语

  JS中的字符串类型是由引号括起来的同样组由16位Unicode字符组成的字符序列。在过去,16号可包含其他字符,直到Unicode引入了扩大字符集,编码规则不得不进行反。本文将详细介绍ES6有关Unicode的连锁扩展

 

概述

  Unicode的对象是为世界上各国一个字符提供唯一标识符,唯一标识符称为码位或码点(code
point)。而这些码位是用于表示字符的,又称之为字符编码(character encode) 

  以ES6之前, JS 的字符串以 16 号字符编码(UTF-16)为根基。每个 16
各类序列(相当给2单字节)是一个编码单元(code
unit),可简称为码元,用于表示一个字符。字符串所有的特性和措施(如length属性与charAt()
方法等)都是根据16各序列

【BMP】

  最常用的Unicode字符使用16各项序列编码字符,属于“基本多语种平面”(Basic
Multilingual Plane BMP),也称“零断面”(plan 0),
是Unicode中之一个编码区段,编码在U+0000——U+FFFF之间。超过此界定的码位则要归于于某辅助平面或叫扩展平面(supplementary
plane),其中的码位仅用16位即无法代表了

  为之,UTF-16引入了代理对(surrogate
pairs),规定用简单个16位编码来表示一个码位。这表示,字符串里的字符来半点种植:一种植由一个码元(共
16 位)来代表BMP字符,另一样种植用少个码元(共 32 位)来表示帮助平面字符

 

大括哀号表示

  JavaScript 允许使用\uxxxx款式表示一个字符,其中xxxx表示字符的
Unicode 码位

// "a"
console.log("\u0061");

  但是,这种代表拟惟有限于码位在\u0000~\uFFFF内的字符。超出这个范围之字符,必须用半单双字节的形式表示

// "𠮷"
console.log("\uD842\uDFB7");

// "₻7"
console.log("\u20BB7");

  上面代码表示,如果直白以\u末端和达到跨0xFFFF的数值(比如\u20BB7),JavaScript会理解成\u20BB+7。所以会来得一个特殊字符,后面就一个7

  ES6 对立即一点做出了改善,只要以码位放入大括号,就能对解读该字符

// "𠮷"
console.log("\u{20BB7}");

// "ABC"
console.log("\u{41}\u{42}\u{43}");

let hello = 123;
// 123
console.log(hell\u{6F}); 

// true
console.log('\u{1F680}' === '\uD83D\uDE80');

  上面代码中,最后一个事例表明,大括哀号表示拟及四字节底 UTF-16
编码是齐价格的。

  有矣这种代表拟下,JavaScript 共有6种植艺术好象征一个字符

'\z' === 'z'  // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

 

字符编解码

【codePointAt()】

  ES6新加了截然支持UTF-16的办法codePointAt(),该措施接受编码单元的职务设不字符位置作参数,返回跟字符串中加以位置对应的码位,即一个整数值

var text = "𠮷a" ;

console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271
console.log(text.charCodeAt(2)); // 97

console.log(text.codePointAt(0)); // 134071
console.log(text.codePointAt(1)); // 57271
console.log(text.codePointAt(2)); // 97

  对于BMP字符,codePointAt()方法的返回值与 charCodeAt()
相同,如’a’,都回97

  对于帮忙平面的32个字符,如’ஷ’,charCodeAt()和codePointAt()方法还分为两有归

  charCodeAt(0)和chatCodeAt(1)分别返回前16个以及后16员之编码;而codePointAt(0)和codePointAt(1)分别返回32各类编码和后16各项的编码 

  判断一个字符是否是BMP,对该字符调用 codePointAt()
方法就是是极简便的办法

function is32Bit(c) {
    return c.codePointAt(0) > 0xFFFF;
}
console.log(is32Bit("𠮷" )); // true 
console.log(is32Bit("a")); // false

  16各项字符的上界用十六进制表示即是FFFF
,因此别大于该数字的码位必须用简单个码元(共32号)表示

【String.fromCodePoint()】

  ES5提供的String.fromCharCode办法,用于打码位返回对许字符,但是这个法子不克鉴别32员之UTF-16字符

  ECMAScript通常会提供正反两栽办法。可以使codePointAt()
来提取字符串内受到有只字符的码位,也可以因String.fromCodePoint()根据加的码位来良成一个字符

console.log(String.fromCharCode(0x20bb7)); // "ஷ"
console.log(String.fromCodePoint(0x20bb7)); // "𠮷"
console.log(String.fromCharCode(0x0bb7)); // "ஷ"

  上面代码中,String.fromCharCode未克辨别大于0xFFFF的码位,所以0x20BB7纵使起了溢起,最高位2受放弃了,最后回来码位U+0BB7对应的字符,而非是码位U+20BB7对应之字符

  如果String.fromCodePoint()办法有差不多只参数,则它们会让合成一个字符串返回

// true
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'

  可以拿 String.fromCodePoint() 视为 String.fromCharCode()
的应有尽有版本。两者处理 BMP 字符时会回去相同结果,只有处理 BMP
范围以外的字符时才会发出距离

 

for…of

  对于32各的支援平面字符来说,使用for或for
in循环,可能得无交对的结果

var s = '𠮷a';
for (let ch in s) {
  console.log(s[ch]);
}
//�
//�
//a

  而for…of循环可以对的辨识32各项的UTF-16字符

var s = '𠮷a';
for (let ch of s) {
  console.log(ch);
}
//𠮷
//a

 

normalize()

  许多欧洲语言来语调符号和重音符号。为了表示她,Unicode提供了个别栽艺术。一种植是直接提供带重音符号的字符,比如Ǒ(\u01D1)。另一样种是供合成符号(combining
character),即原字符与重音符号的合成,两独字符合成一个字符,比如O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C)

  这半种象征法,在视觉及语义上还当,但是JavaScript不克鉴别

console.log('\u01D1'==='\u004F\u030C'); //false

console.log('\u01D1'.length); // 1
console.log('\u004F\u030C'.length); // 2

  上面代码表示,JavaScript将合成字符视为零星个字符,导致个别栽象征法无抵。

  ES6供字符串实例的normalize()术,用来用字符的不同代表方法统一吗平的款型,这称之为Unicode正规化

console.log('\u01D1'==='\u01D1'.normalize()); //true
console.log('\u01D1'=== '\u004F\u030C'.normalize()); //true

normalize方式可领一个参数来指定normalize的不二法门,参数的季单可选值如下

  1、NFC,默认参数,表示“标准等于合成”(Normalization Form Canonical
Composition),返回多独大概字符的合成字符。所谓“标准等于”指的是视觉和语义上的当

console.log('\u01D1'==='\u01D1'.normalize("NFC")); //true
console.log('\u01D1'=== '\u004F\u030C'.normalize("NFC")); //true

  2、NFD,表示“标准等价分解”(Normalization Form Canonical
Decomposition),即当正式等的前提下,返回合成字符分解的大都只简易字符

console.log('\u004F\u030C'==='\u01D1'.normalize("NFD")); //true
console.log('\u004F\u030C'=== '\u004F\u030C'.normalize("NFD")); //true

  3、NFKC,表示“兼容等价格合成”(Normalization Form Compatibility
Composition),返回合成字符。所谓“兼容等价”指的凡语义上是等,但视觉上无对等,比如“囍”和“喜喜”。(这只是用来比喻,normalize方法无克辨识中文。)

  4、NFKD,表示“兼容等价格分解”(Normalization Form Compatibility
Decomposition),即以相当等价格的前提下,返回合成字符分解的大半独简易字符

  以开国际化应用时,normalize()
方法充分实用。但normalize()办法目前未克鉴别三只或三独以上字符的合成。这种景象下,还是只能使用正则表达式,通过Unicode编号区间判断

 

U修饰符

  正则表达式可以形成简单的字符串操作,但默认将字符串中之各个一个字符按照16位编码处理。为了解决是题材, ES6
对正则表达式添加了u修饰符,含义为“Unicode模式”,用来正确处理大于\uFFFF
Unicode 字符。也就是说,会正确处理四只字节的 UTF-16 编码

/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true

  一旦为正则表达式设置了 u
修饰符,正则表达式将会见识别32号的提携平面字符为1个字符,而不是鲜只

【点号】

  点(.)字符在正则表达式中,含义是除换行符以外的轻易单个字符。对于码位大于0xFFFF
Unicode 字符,点字符不能够识别,必须抬高u修饰符

var text = "𠮷" ;
console.log(text.length); // 2
console.log(/^.$/.test(text));//false
console.log(/^.$/u.test(text)); //true

【大括号】

  ES6 新增了动大括声泪俱下表示 Unicode
字符,这种代表拟以正则表达式中必长u修饰符,才会鉴别当中的大括声泪俱下,否则会为解读呢量词

/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true

【量词】

  使用u修饰符后,所有量词都见面是认识别码点大于0xFFFF的 Unicode 字符

/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true

【预定义模式】

  u修饰符也影响及预定义模式,能否正确认识别码点大于0xFFFF的 Unicode
字符

/^\S$/.test('𠮷') // false
/^\S$/u.test('𠮷') // true

【字符串长度】

  上面代码的\S凡是预定义模式,匹配有未是空格的字符。只有加了u修饰符,它才会对匹配码点超过0xFFFF
Unicode 字符

  虽然ES6未支持字符串码位数量的检测,length属性仍然返回字符串编码单元的多寡。利用[\s\S],再加上u修饰符,就得写有一个是返回字符串长度的函数

function codePointLength(text) {
  var result = text.match(/[\s\S]/gu);
  return result ? result.length : 0;
}

var s = '𠮷𠮷';

console.log(s.length); // 4
console.log(codePointLength(s)); // 2

【检测支持】

  u修饰符是语法层面的变更,尝试在不匹配 ES6 的 JS
引擎中以它们见面丢弃来语法错误。如果如检测时发动机是否支持u修饰符,最安全之计是经过以下函数来判定

function hasRegExpU() {
    try {
        var pattern = new RegExp(".", "u");
        return true;
    } catch (ex) {
        return false;
    }
}

  这个函数使用了RegExp构造函数并传播字符串’u’作为参数,该语法即使在旧版
JS 引擎中吗是行得通之。但是,如果手上滋生擎不支持u修饰符则会扔来荒谬