ES6字符串和正则

字符串,常见于各种高级编程语言。正则,许多高级语言原生支持。两个都很重要,因此ES6进一步完善相关功能。

更好的Unicode支持

ES6之前,JS字符串基于16位字符编码(UTF-16),每16位是一个编码单元(code unit),用来代表一个字符。
length,charAt方法都是基于这种编码方式。

UTF-16码位

  • Unicode目的是给每一个字符提供唯一的数字标识,也称为码位(code point),从0开始。但是,时代变了,现在字符需求数超过了16位,导致原来的16个码位不足以表示。表示字符的数字标识(码位),称为字符编码(character encode)。意思就是,ES6之前,一个码位就是一个字符编码,就是一个编码单元。
  • 现在,ES6中,UTF-16的代理对(surrogate pair),规定,用两个16位编码单元表示一个码位。这样就可以表示那些之前无法表示的字符了。

简而言之,ES6现在字符有两种表示方式:

  • 16位的字符,即只有一个编码单元
  • 32位的字符,代理对,包含两个编码单元

ES5所有的字符串操作基于16位的字符(即使此字符使用32位表示的)。
ES5代码,IE11控制台的运行结果:

var e = '😅';
=> undefined
e.length
=> 2
/^.$/.test(e)
=> false
e.charAt(0)
=> "���"
e.charAt(1)
=> "���"
e.char
=> undefined
e.charCodeAt(0)
=> 55357
e.charCodeAt(1)
=> 56837

长度属性是2,而且第一个和第二个编码单元不是一个BMP,显示乱码。

codePointAt方法

ES6新增方法。完全支持UTF-16。
方法的参数为编码单元的位置,返回此位置的码位,即一个非负整数。

var e = '😅a';
=> undefined
e.length
=> 3
e.codePointAt(0)
=> 128517
e.codePointAt(1)
=> 56837
e.codePointAt(2)
=> 97

e.charCodeAt(0)
=> 55357
e.charCodeAt(1)
=> 56837
e.charCodeAt(2)
=> 97

可以看到,对于16位字符,其charCodeAt与codePointAt方法返回值相同。
对于扩展32位的字符,由于其包含两个编码单元,所以其length值2
但是,e.codePointAt(0)返回的是一个完整的UTF-16编码,而前半个16位编码,是大于0xFFFF的。因此,可以借此判断字符占用的编码单元数量。

//判断一个字符是否是32位的编码单元表示的
function is32Bit(c) {
    return c.codePointAt(0) > 0xFFFF;
}

String.fromCodePoint方法

此静态方法可以看作完整版的String.fromCharCode方法,对于16位编码单元的字符,两者返回的结果一样。

String.fromCodePoint(128517)  // 😅

normalize方法

Unicode会存在一种情况,代表相同的文本的两个字符串包含不同的码位序列。
因此,比较字符串时,需要将这种等效标准化。
所以在排序和比较字符串时,需要先运行normalize。
这在设计国际化应用时很必要。

values.sort(function(first, second){
    let firstNormalized = first.normalize(), secondNormalized = second.normalized();
    if (firstNormalized < secondNormalized) {
        return -1;
    } else if (firstNormalized > secondNormalized) {
        return 1;
    } else {
        return  0;
    }
});

正则的u修饰符

以下方法忽略ES6的正则修饰符uy

String.prototype.search(regExp)
String.prototype.split(regExp)

正则默认将字符串的字符按照16位的编码单元处理。ES6增加了u修饰符用来支持Unicode编码方式。
检测字符长度(适合较短字符串):

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

其他字符串变更

四个原型方法。用于子串识别和重复文本。

includes方法,检测出指定文本,返回布尔值,索引可自定义,默认0。
startsWith方法,字符串起始部分是否匹配指定文本,返回布尔值,起始部分索引可自定义,默认0。
endsWith方法,字符串结束部分是否匹配指定文本,返回布尔值,索引可自定义,默认str.length。
此三个方法不接受正则。
repeat方法,重复指定次数的字符串。