在多次尝试理解之后,我不得不说我不明白String.prototype.normalize()
是如何工作的。该方法可以取NFC
、NFD
、NFKC
、NFKD
作为参数。
首先,我不明白NFD
和NFKD
的区别是什么。说明书对此非常模糊,所以……在一些资源中,我读到NFD
通过规范等价来分解字符。例如:
"â" (U+00E2) -> "a" (U+0061) + " ̂" (U+0302)
和NFKD
按兼容性对字符进行分解。例如:
"fi" (U+FB01) -> "f" (U+0066) + "i" (U+0069)
但这并不完全正确。NFKD
不仅根据兼容性分解字符。它还可以完美地处理第一个例子:
let s = `u00E2`; //"â"
console.log(s.normalize('NFD').length); //2
console.log(s.normalize('NFKD').length); //2
这是否意味着NFKD
可以通过兼容性和规范等价来分解字符?NFD
只通过规范等价来分解字符…?
let s = `uFB01`; //"fi"
console.log(s.normalize('NFD').length); //1
Unicode
选择的完全分解类型取决于哪个Unicode涉及到归一化形式。对于NFC或NFD,一个人做一个完整的正则分解,它只使用正则Decomposition_Mapping值。对于NFKC或NFKD,一个人做一个完整的兼容性分解,它使用规范的和
这就是为什么NFC/NFD和NFKC/NFKD是这样工作的:
let s1 = 'uFB00'; //"ff"
let s2 = 'u0066u0066'; //"ff"
console.log(s1.normalize('NFD').length); //doesn't work with compatible -- only can. eq.
let t1 = `u00F4`; //ô
let t2 = `u006Fu0302`; //ô
console.log(t1.normalize('NFKD').length); //also works with can. eq.
console.log(t2.normalize('NFKC').length); //also works with can. eq.
这完全可以理解,因为…
MDN
所有标准等价序列也兼容,但反之则不兼容。