美文网首页
10-字符串扩展-Unicode

10-字符串扩展-Unicode

作者: 早起的鸟儿 | 来源:发表于2019-11-02 15:15 被阅读0次

ES6加强了对Unicode的支持,并且扩展了字符串对象。

一、字符的Unicode表示法

JavaScript允许采用\uxxxx形式表示一个字符,其中“xxxx”表示字符的码点。

{
    let str = '\u0062';   //js采用十六进制编码格式存储值 范围是\u0000--\uFFFF
    console.log(str)  //b
}

但是,这种表示法只限于\u0000——\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表达。

let str = '\uD842\uDFB7';   //UTF-16编码
console.log(str);    // "𠮷"
    
let str1 = "\u20BB7"   //码点
console.log(str1);    // " 7"

上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7

二、ES6改进(加花括号)
let str = '\u{20BB7}';     
console.log(str);    // "𠮷"  

'\u{20BB7}'=='\uD842\uDFB7'   //true 
三、方法

JavaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode码点大于0xFFFF的字符),JavaScript会认为它们是两个字符,超出这个范围的字符,必须用两个双字节的形式表达。

  1. charAt()方法 (返回字符串给定位置的字符)
*********超出范围***********
{
    let str = "𠮷";
    console.log(str.length);   //2   
    console.log(str.charAt(0));  //�
    console.log(str.charAt(1));  //�
}

*********范围之内***********
{
    let str = "吉";
    console.log(str.length);   //1  
    //length得到的是字符的长度,而不是字节的长度,一个汉字和一个英文的length都应该是1
    console.log(str.charAt(0));  //吉
}

上面代码中,汉字“𠮷”(注意,这个字不是”吉祥“的”吉“)的码点是0x20BB7,UTF-16编码为0xD842 0xDFB7(十进制为55362 57271),需要4个字节储存。对于这种4个字节的字符,JavaScript不能正确处理,字符串长度会误判为2,而且charAt方法无法读取整个字符,如果用charCodeAt方法只能分别返回前两个字节和后两个字节的值。

  1. charCodeAt()方法(返回的是十进制值)
//charCodeAt方法
{
  let str = "𠮷";
  console.log(str.charCodeAt(0).toString(16));  //d842
  console.log(str.charCodeAt(1).toString(16));  //dfb7

  等同于:

  //\uD842\uDFB7(UTF-16编码)
}
  1. codePointAt()方法(返回值是十进制)

ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点,codePointAt方法的参数,是字符在字符串中的位置(从0开始)。

{
    let str = "𠮷a";
    console.log(str.codePointAt(0).toString(16))  // "20bb7"
    console.log(str.codePointAt(1).toString(16))  // "dfb7"
    console.log(str.codePointAt(2).toString(16))  // "61"
}

你可能注意到了,codePointAt方法的参数,仍然是不正确的。比如,上面代码中,字符a在字符串str的正确位置序号应该是1,但是必须向codePointAt方法传入2。解决这个问题的一个办法是使用for...of循环,因为它会正确识别32位的UTF-16字符

{
    let str = "𠮷a";
    for(let s of str) {
       console.log(s.codePointAt().toString(16)) // "20bb7" "61"
    }
}

应用场景:判断当前字符是否大于0xFFFF

{
    function fn(str){
        return str.codePointAt(0) > 0xFFFF;
    }
    console.log(fn("你"))  //false
    console.log(fn("𠮷"))  //true
}
  1. at()方法:

ES5对字符串对象提供charAt方法,返回字符串给定位置的字符。该方法不能识别码点大于0xFFFF的字符。

{
    console.log('abc'.charAt(0));   // "a"
    console.log('𠮷'.charAt(0));    // "�"
}

上面代码中,charAt方法返回的是UTF-16编码的第一个字节,实际上是无法显示的。

目前,有一个提案,提出字符串实例的at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。

{
    console.log('abc'.at(0));   // "a"
    console.log('𠮷'.at(0));    // "𠮷"
}

这个方法可以通过垫片库pollfiy实现。

总结:

ES5

  1. charAt()返回指定位置的字符,前提是不大于0xFFFF的字符;如果大于0xFFFF的字符,返回一个不识别的字符。
  2. charCodeAt()返回指定位置的字符十进制码点;如果是一个大于0xFFFF的字符,则分别返回前两个字节和后两个字节的的十进制值。

ES6

  1. at()返回指定位置的字符,修正了charAt()不能解析大于0xFFFF的字符。
  2. codePointAt()使用for...of循环,能够正确处理4个字节储存的字符,返回一个字符的码点。

相关文章

网友评论

      本文标题:10-字符串扩展-Unicode

      本文链接:https://www.haomeiwen.com/subject/fcncmctx.html