zoukankan      html  css  js  c++  java
  • ES6类型扩展Unicode扩展

    JS中的字符串是一组由引号包裹的16位Unicode字符组成的字符序列。在Unicode引入扩展字符集之后,JS中的Unicode编码规则也进行了变更,本文介绍ES6中关于Unicode的相关扩展。

    基本概念

    Unicode的目标是为世界上每一个字符提供唯一标识符。唯一标识符(code point)也叫作码位或码点,码位又称标识符的字符编码。

    ES6之前,JS的字符串以16位字符编码(UTF-16)为基础,每个16位字符序列(2个字节)是一个编码单元(code unit),简称码元。字符串所有的属性和方法都是基于16位字符序列。

    BMP

    最常用的Unicode字符使用16位编码序列字符,属于“基本多语种平面”(Basic Multilingual Plane BMP),又称“零断面”(plan 0)。BMP是Unicode中的一个编码区段,编码介于U+0000到U+FFFF之间,超过这个范围的码位则属于某个辅助平面(supplementary plane),又称扩展平面,这些码位用16位字符已无法表示。

    为了解决辅助平面码位的表示问题,UTF-16引入了代理对(surrogate pairs),规定用两个16位编码来表示一个码位,这意味着字符串中字符有两种:一种是用一个码元来表示的BMP字符(16位);另一种是用两个码元表示的辅助平面字符(32位)

    表示方法

    JS允许采用\uxxxx形式表示一个字符,xxxx表示字符的Unicode码位。这种表示法只限于码位在\u0000 ~ \uFFFF之间的字符,超出该范围必须用两个双字节形式表示。

    console.log('\u0061') // a
    console.log('\uD842\uDFB7') // 
    console.log('\u20BB7') // ₻7
    

    \u20BB7由于超出了表示范围,js会理解成'\u20BB'+'7',所以最终显示一个“₻7“

    ES6对这点做出了改进,只要把码位放到大括号里就能正确读取该字符。

    console.log('\u{20BB7}') // 
    console.log('\u{20BB7}' === '\uD842\uDFB7') // true
    console.log('\u{0061}') // a
    

    现在同一个字符,有下面几种表示方法:

    console.log('\a' === 'a') // true
    console.log('\x61' === 'a') // true
    console.log('\u0061' === 'a') // true
    console.log('\u{61}' === 'a') // true
    

    字符编解码

    codePointAt()

    ES6新增了codePointAt()方法,该方法接收编码单元的位置作为参数(非字符串位置),返回字符串中给定位置对应的Unicode码位。

    注意: charCodeAt()方法接收字符串位置作为参数,返回字符串中给定位置对应的Unicode码位。

    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位的编码

    可以使用codePointAt() 方法判断一个字符是否位于BMP。

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

    String.fromCodePoint()

    String.fromCodePoint()方法是codePointAt()的反向操作,该方法返回给定码位所对应的字符。

    注意: String.fromCharCode()方法也用于返回给定码位所对应的字符,但是它不能识别32位的UTF-16字符。

    console.log(String.fromCodePoint(0x20bb7)); // 
    console.log(String.fromCodePoint(0x61)); // a
    
    console.log(String.fromCharCode(0x20bb7)); // ஷ
    console.log(String.fromCharCode(0x61)); // a
    

    String.fromCodePoint()方法同样可以接收多个参数,返回合并后的字符串

    String.fromCodePoint(104,101,108,108,111) // hello
    

    normalize()

    许多欧洲语言有语调符号和重音符号,例如Ǒ。Unicode提供了两种方式表示这些特殊符号。一种是直接提供带重音符号的字符,比如Ǒ('\u01D1')。另一种是通过合成原字符和重音符,比如oˇ('\u004F\u030C')

    这两种表示方式在视觉上是相同的,但是JS无法识别

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

    normalize()方法可以把字符的不同表示方式统一成相同的形式,这样JS就能正确识别了,这称为Unicode正规化。

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

    normalize()方法可以接受一个参数来指定normalize的方式,参数的四个可选值如下:

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

    2、NFD,表示“标准等价分解”(Normalization Form Canonical Decomposition),即在标准等价的前提下,返回合成字符分解的多个简单字符

    3、NFKC,表示“兼容等价合成”(Normalization Form Compatibility Composition),返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如“囍”和“喜喜”。(这只是用来举例,normalize方法不能识别中文。)

    4、NFKD,表示“兼容等价分解”(Normalization Form Compatibility Decomposition),即在兼容等价的前提下,返回合成字符分解的多个简单字符

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

    在开发国际化应用时normalize()方法很有用,但它不能识别三个或三个以上字符的合成。这时候只能通过正则表达式,对Unicode编号区间进行判断。

    U修饰符

    ES6之前的正则表达式不能正确处理32位编码的字符,ES6为正则表达式添加了u修饰符,含义为“Unicode模式”,让它可以正确处理大于\uFFFF的 Unicode 字符,即32位编码的字符。

    console.log(/^\uD842/.test('\uD842\uDFB7')) // true
    console.log(/^\uD842/u.test('\uD842\uDFB7')) // false
    

    设置u修饰符后,位于辅助平面的32位字符会被识别为1个字符。

    元字符.

    元字符.,在正则表达式中含义是匹配除了换行符外的任意单个字符。对于码位大于0xFFFF的Unicode字符,必须加上u修饰符才能正常识别。

    let s = ''
    console.log(s.length); // 2
    console.log(/^.$/.test(s));//false
    console.log(/^.$/u.test(s)); //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}/u.test('aa') // true
    /{2}/u.test('') // true
    
    /a{2}/.test('aa') // true
    /{2}/.test('') // false
    

    预定义模式

    \S表示预定义模式,匹配所有非空格的字符。只有加了u修饰符才能正确匹配码点大于0xFFFF的 Unicode 字符

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

    字符串长度

    ES6不支持字符串码位数量的检测,所以length属性仍然返回字符串编码单元的数量。但是可以利用[\s\S]结合u修饰符,写出一个正确返回字符串长度的函数。

    function codePointLength(text) {
      var result = text.match(/[\s\S]/gu);
      return result ? result.length : 0;
    }
    
    var s = '';
    
    console.log(codePointLength(s)); // 2
    console.log(s.length); // 4
    
    优秀文章首发于聚享小站,欢迎关注!
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/yesyes/p/15352126.html
Copyright © 2011-2022 走看看