当一个字符串不再是字符串?JavaScript中的Unicode规范化问题

18

在使用 .normalize() 的 Unicode 标准化函数时,我在Firefox中遇到了一些严重的字符串行为问题。

这里是一个演示,在Firefox浏览器中查看控制台可见问题。

假设我有一个id为“NFKC”的按钮:

<button id="NFKC">NFKC</button>

获取对它的引用,很容易:
document.querySelector('#NFKC')
// <button id="NFKC">

现在,由于此按钮具有NFKC的id,我们可以按以下方式获取该字符串:

document.body.querySelector('#NFKC').id
// "NFKC"

将该字符串存入一个变量中:

var s1 = document.body.querySelector('#NFKC').id

与之相比,直接将同样的字符串赋值给一个变量:

var s2 = 'NFKC'

当然:

s1 === s2
// true

与:

s1 == s2
// true

现在该是我头爆炸的时候了。

要对字符串进行规范化,您需要将 NFCNFDNFKCNFKD 之一传递给 .normalize() 方法,像这样:

'á'.normalize('NFKC')
// "á"

当然,根据您选择的规范化形式,您会得到不同的码点,但无论如何。

'á'.normalize('NFC').length == 1
// true
'á'.normalize('NFD').length == 2
// true

无论如何,重点是将四个字符串中的一个传递给.normalize(),然后你将得到一个规范化的字符串。

既然我们知道s1(从DOM检索出来的字符串)和s2是相同的字符串(s1 === s2true),那么显然我们可以使用任何一个字符串来规范化一个字符串:

'á'.normalize(s2)
"á"
// well yeah, because s2 IS 'NFKC'. 

自然,s1 会以完全相同的方式运作,对吗?

'á'.normalize(s1)
 // RangeError: form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'

不好意思。

那么问题是:为什么在使用.normalize()时,s1 === s2成立但s1s2看起来却不相等?

这种情况在我目前测试的其他浏览器中没有发生,只有在Firefox中出现了这个问题。

更新

这是Firefox中的一个错误,已经被修复了,请查看这个链接


2
@pat 我认为这显然不是正确的行为;这看起来像是一个非常明显的错误,需要提交到 FF bug 跟踪器中。 - apsillers
4
我已经在https://bugzilla.mozilla.org/show_bug.cgi?id=1145326上添加了一个错误报告。 - user2467065
2
我找到了Firefox中String.prototype.normalizeC++实现代码。看起来问题与formStr的设置有关。 - apsillers
4
不仅是 DOM 的问题。这些也失败了:var s2 = 'NFKC'.split('').join('');var s2= 'NFKCabc'.replace('abc','');。但是这个没有问题:var s2= 'N'+'F'+'K'+'C';。很奇怪。 - Rick Hitchcock
4
你可以将你的更新发布为答案并接受它吗?顺便恭喜你发现了这个漏洞! - Nickolay
显示剩余8条评论
1个回答

1
我不确定这是否有帮助,但文档表明:

这是实验性技术,是Harmony(ECMAScript 6)方案的一部分。由于该技术规范尚未稳定,请查看兼容性表以在各种浏览器中使用它。此外,请注意,实验性技术的语法和行为可能会随着规范的变化而在将来的浏览器版本中发生变化。

而兼容性表格如下:
Feature         Chrome  Firefox (Gecko) Internet Explorer           Opera   Safari
Basic support   34      31 (31)         11 on Windows 10 Preview    (Yes)   Not supported

然而,此页面的最后更新日期为2014年11月18日。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接