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
    
    优秀文章首发于聚享小站,欢迎关注!
  • 相关阅读:
    ElasticSearch(ES)学习笔记
    Lucene學習日志
    velocity代码生成器的使用
    springboot学习笔记
    springmvc json 类型转换错误
    在做del业务时,传递参数,和接口中入参注释
    做add添加业务时,字符集乱码,form标签库,button的href 问题,添加后页面跳转,forward,redirect 。定制错误输出
    mybatis中联合查询的返回结果集
    mybatis分页,绝对路径的2种写法
    maven导入项目时报错,配置应用程序监听器[org.springframework.web.context.ContextLoaderListener]错误
  • 原文地址:https://www.cnblogs.com/yesyes/p/15352126.html
Copyright © 2011-2022 走看看