今天,我偶然发现了JavaScript / ECMAScript国际化API中一个奇怪的问题,我在任何地方都找不到合适的解释。在比较两个特定字符-正斜杠(/)和下划线(_)字符时,我得到了不同的结果:
Intl.Collator.prototype.compare()方法基于平原/传统UTF-16的比较
// Vanilla JavaScript comparator
const cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
console.log(cmp('/', '_'));
// Output: -1
// When sorting
const result = ['/', '_'].sort(cmp);
console.log(result);
// Output: ['/', '_']
Intl.Collator.prototype.compare()方法
const collator = new Intl.Collator('en', {
sensitivity: 'base',
numeric: true
});
console.log(collator.compare('/', '_'));
// Output: 1
// When sorting
const result = ['/', '_'].sort(collator.compare);
console.log(result);
// Output: ['_', '/']
问题
为什么这两种技术产生不同的结果?这是ECMAScript实现中的一个bug吗?我在这里漏掉了什么?是否还有其他这样的字符组合会对英语(en)语言/地区产生不同的结果?
编辑2021-10-01
正如@t crowder所指出的,将所有"ASCII“替换为"UTF-16”。
发布于 2021-10-01 12:31:49
总体而言
当您在字符串上使用<和>时,会根据它们的UTF-16代码单元值进行比较(不是ASCII,但是ASCII与许多常见字符的值重叠)。温和地说,这是有问题的。例如,问问法语中的"z" < "é"是否真的应该是真的(表示z在é之前):
console.log("z" < "é"); // true?!?!
当您使用Intl.Collator.prototype.compare时,它会根据您提供的选项为您的地区使用适当的排序规则(松散地排序)。在许多情况下,这可能是与UTF-16代码单元值的结果不同的。例如,即使在en区域设置中,Collator也返回z在é之后出现的更合理的结果
console.log(new Intl.Collator("en").compare("z", "é")); // 1
_和/
我无法具体地告诉您,为什么_和/与您使用的UTF-16代码单元有不同的顺序(以及我正在使用的代码单元),无论是en-US、en-UK还是其他什么。但是,发现ASCII和Unicode之间的顺序不同并不令人惊讶。(请记住,_和/的UTF-16代码单元值来自于它们的ASCII值。)
ASCII的顺序是在20世纪60年代初精心设计的(有关于它的精彩细节的PDF ),但除了A和0-9的排序之外,基本上不涉及语言排序。/从1963年起就在最初的ASCII中。直到1967年,_才被添加到一个比/更高的可用位置。在ASCII中,可能没有比这更重要的原因了,为什么_比/晚/高(数字)。
Unicode的排序顺序是在1990年代(一直到今天)仔细设计的,有不同的目标(包括语言目标)、设计要求和设计约束。据我所知(我不是Unicode专家),TR10和TR35的第5部分描述了Unicode的排序规则。我还没有找到_在根排序规则中位于/之前的具体理由(en使用根排序规则)。我肯定它就在里面。我确实注意到,它的一个方面似乎是按类别分组。_的类别是"Connector标点符号“,而/的类别是”其他标点符号“。也许这与/比_晚的原因有关。
但基本答案是:它们不同,因为ASCII的排序和Unicode排序是根据不同的约束和需求设计的。
https://stackoverflow.com/questions/69405786
复制相似问题