javascript - 为什么 JavaScript `Intl.Collator.prototype.compare()` 方法会产生与传统 UTF-16 比较特殊字符不同的结果?
问题描述
今天,我偶然发现了一个关于 JavaScript / ECMAScript 国际化 API 的奇怪问题,我在任何地方都找不到合适的解释。/
比较两个特定字符 - 正斜杠 ( ) 和下划线 ( ) 字符时,我得到了不同的结果_
:
- 普通香草/传统的基于 UTF-16 的比较
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 实现中的错误吗?我在这里错过/无法理解什么?是否还有其他此类字符组合会为英语 ( en
) 语言/区域设置产生不同的结果?
编辑 2021-10-01
正如@tj-crowder 指出的那样,将所有“ASCII”替换为“UTF-16”。
解决方案
一般来说
当您在字符串上使用<
和>
时,它们会根据它们的 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
,无论是en-US
,en-UK
还是其他。但发现它们的顺序在 ASCII 和 Unicode 之间有所不同也就不足为奇了。(请记住,UTF-16 代码单元值来自它们的 ASCII 值。_
)/
ASCII 的顺序是在 1960 年代初精心设计的(有一个PDF详细介绍了它),但除了 AZ 和 0-9 的顺序之外,基本上没有考虑语言顺序。从 1963 年开始使用原始 ASCII。直到 1967 年才被添加到一个可用位置,其数值高于. 可能没有比ASCII更晚/更高(数字上)的原因。/
_
/
_
/
Unicode 的排序规则在 1990 年代(一直到今天)经过精心设计,具有不同的目标(包括语言目标)、设计要求和设计约束。据我所知(我不是 Unicode 专家),TR10和TR35的第 5 部分描述了 Unicode 的排序规则。_
我还没有找到为什么在根排序规则中之前的具体理由/
(en
使用根排序规则)。我确定它就在某个地方。我确实注意到它的一个方面似乎是按类别分组。的类别_
是“连接符标点符号”,而 的类别/
是“其他标点符号”。也许这与为什么/
迟于_
.
但基本的答案是:它们不同,因为 ASCII 的排序和 Unicode 排序规则是根据不同的约束和要求设计的。
推荐阅读
- common-lisp - 对单个文件使用 ASDF 的 :around-compile
- sql - SQL 在多对多关系中查找不属于特定集合的所有元素
- python - Python:如何改进重复代码?
- excel - VBA: if-else-statement 运行时错误'-2147417848 (80010108)'
- c# - Blazor 基于角色的授权 - 没有“Microsoft.AspNetCore.Identity.RoleManager”类型的服务
- javascript - Angular Karma 测试:方法不会改变类属性?
- java - 我得到的错误:方法 myMethod(int[]) 对于 ArityMethod 类型不明确
- vue.js - Uncaught (in promise) TypeError: Cannot read property 'length' of undefined in chartjs with Vuejs
- python - django.db.utils.ProgrammingError:关系“...”不存在
- android - 如何使用 React Native 生成 android APK 文件?