字符串中的字符有两种,一种是由一个编码单元16位表示的BMP(Basic Multilingual Plane)字符,另一种是由两个编码单元32位表示的辅助平面字符。
在ES5中,所有字符串的操作都是基于16位编码单元。
codePointAt()方法
ES6中新增加里完全支持UTF-16的codePointAt()方法.
codePointAt接受编码单元的位置而非字符位置作为参数,返回与字符串中给定位置对应的码位,即一个整数值。
let txt='𠮷a' console.log(txt.charCodeAt(0))//55362 --仅仅返回位置0处的第一个编码单元 console.log(txt.charCodeAt(1))//57271 console.log(txt.charCodeAt(2))//97 console.log(txt.codePointAt(0))//134071 --返回完整的码位,即使这个码位包含多个编码单元 console.log(txt.codePointAt(1))//57271 console.log(txt.codePointAt(2))//97
也就是说对于BMP字符集中的字符,codePointAt方法的返回值与charCodeAt方法的相同,而对于非BMP字符集来说返回值则不同。
- charCodeAt()返回的只是位置0处的第一个编码单元。
- codePointAt()返回完整的码为,即使这个码位包含多个编码单元。
检测字符占用编码单元数量
function is32Bit(c) {
return c.codePointAt(0)>0xFFFF
}
console.log(is32Bit('?'))//true
console.log(is32Bit('a'))//false
String.fromCodePoint()方法
- codePointAt()方法是通过在字符串中检索一个字符的码位。
- String.fromCodePoint()方法是根据制定的码位生成一个字符。
console.log(String.fromCodePoint(134071)) // 𠮷
normalize()方法
在对不同字符进行排序或比较时,会存在一种可能:它们是等效的。
1、规范的等效是指无论从哪个角度来看,两个序列的码位都是没有区别的
2、两个互相兼容的码位序列看起来不同,但是在特定情况下可以被交换使用
切记:在对比字符串前一定要把它们标准化为同一种形式
let values = ["test", "demo", "demo","compare", "sort"] let normalized = values.map(function (txt) { return txt.normalize() }) normalized.sort(function (first, second) { if (first < second) console.log(-1) else if (first === second) console.log(0) else console.log(1) })
上述代码也可以写成如下的格式:
let values = ["test", "demo", "compare", "sort"] values.sort(function (first, second) { // let firstNormalized = first.normalize(), // secondNormalized = second.normalize(); //可以写成这种形式也可以写成如下这种形式,默认NFC格式,也可以明确制定其他形式。 let firstNormalized = first.normalize('NFC'), secondNormalized = second.normalize('NFC'); if (firstNormalized < secondNormalized) return -1 else if (firstNormalized === secondNormalized) return 0 else return 1 })
Unicode标准化形式:
- NFC(Normalization From Canonical),默认参数,表示“标准等价合成”,返回多个简单字符的合成字符。所谓“标准等价”指的是视觉和语义上的等价。
- NFD(Normalization From Canonical Decompositon),表示“标准等价分解”,即在标准等价的前提下,返回合成字符分解的多个简单字符。
- NFKC(Normalization From Compatibility Composition),表示“兼容等价合成”,返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如“囍”和“喜喜”。(此处用来举例,
normalize ()
方法不能识别中文。) - NFKD(Normalization From Compatibility Decompositon),表示“兼容等价分解”,即在兼容等价的前提下,返回合成字符分解的多个简单字符。
正则表达式u修饰符
当一个正则表达式使用u修饰符时,它就从编码单元操作切换为字符模式。
u修饰符实例
let txt = '𠮷' console.log(txt.length)//2 console.log(/^.$/.test(txt))//false console.log(/^.$/u.test(txt))//true
正则表达式
/^.$/
匹配所有单字符字符串。
计算码位数量
function codePointLength(txt) { let result = txt.match(/[\s\S]/g) return result ? result.length : 0 } function codePointLengthWithu(txt) { let result = txt.match(/[\s\S]/gu) return result ? result.length : 0 } console.log(codePointLength('abc'))//3 console.log(codePointLength('𠮷ab'))//4 console.log(codePointLengthWithu('abc'))//3 console.log(codePointLengthWithu('𠮷ab'))//3 console.log('𠮷ab'.length)//4
调用match()方法检查空白和非空白字符,使用
[\s\S]
来确保这个模式能够匹配新行。
检测引擎是否支持u修饰符
function hasRegExpU(params) { try { var pattern = new RegExp(".", "u") return true } catch (ex) { return false } }
如果你的代码仍然需要运行在老式的JS引擎中,使用修饰符时切记使用RegExp构造函数,这样可以避免发生语法错误,并且你可以有选择的检测和使用u修饰符而不会造成系统异常终止。
其他字符串变更
字符串中的子串识别
- includes() 在字符串中检测是否包含指定文本
- startsWith() 在字符串的起始部分是否包含指定文本
- endsWith() 在字符串的结束部分是否包含指定文本
以上三个方法都接受两个参数:1、要搜索的文本 2、(可选)开始搜索的索引值,如果指定的第二个参数则会比这个索引值的位置开始匹配,endsWith则从字符串长度减法这个索引值的位置开始匹配。
let msg = 'Hello world!'
console.log(msg.startsWith('Hello'))//true
console.log(msg.endsWith('!'))//true
console.log(msg.includes('o'))//true
console.log(msg.startsWith('o'))//false
console.log(msg.endsWith('world!'))//true
console.log(msg.includes('x'))//false
console.log(msg.startsWith('o', 4))//true--从字符串Hello中的‘o’开始
console.log(msg.endsWith('o', 8))//true--索引值为8的字符为‘r’,字符串减去‘r’及之后的字符串后开始匹配。
console.log(msg.includes('o', 8))//false--从字符串world中的r开始匹配
通过indexOf()和lastIndexof()寻找子串的位置,并且如果传一个正则表达式进去的话,它们会将传入的正则表达式转化为字符串并搜索它,而在includes()、startsWith()、endsWith()这三方法中,如果你不是传入字符串而是一个正则表达式则会报错。
repeat()方法
repeat()方法接受一个number类型的参数,表示该字符串的重复次数,返回当前字符串重复一定次数后的新字符串。
console.log('x'.repeat(3))//xxx
console.log('hello'.repeat(2))//hellohello