如何控制排序时大写字母或小写字母优先
使用 Intl.Collator 的 caseFirst 选项来确定字符串排序时的大小写顺序
简介
当你对仅大小写不同的字符串数组进行排序时,JavaScript 需要决定哪种形式排在前面。是 apple 应该排在 Apple 前面,还是 Apple 应该排在 apple 前面?不同的应用对这种排序顺序有不同的需求。
默认情况下,仅大小写不同的字符串的排序顺序取决于区域设置和敏感度设置。在许多情况下,像 apple 和 Apple 这样的字符串会被视为相等,导致它们的顺序不可预测。如果你的应用对大小写排序有要求,就需要明确控制大写字母还是小写字母优先。
Intl.Collator API 提供了 caseFirst 选项,用于决定大小写排序顺序。你可以配置排序器让大写字母排在小写字母前、小写字母排在大写字母前,或者使用区域设置的默认行为。本教程将介绍 caseFirst 选项的工作原理、其生效条件,以及如何在实际排序场景中使用它。
caseFirst 选项的作用
caseFirst 选项用于控制仅大小写不同的字符串的排序顺序。它接受三个字符串值:"upper"、"lower" 或 "false"。
当设置为 "upper" 时,大写字母会排在对应的小写字母前。例如,字符串 Apple 会排在 apple 前面。
当设置为 "lower" 时,小写字母会排在其大写字母之前。例如,字符串 apple 会排在 Apple 之前。
当设置为 "false"(字符串值,而不是布尔值)时,排序器会使用该语言环境的默认大小写顺序。如果未指定该选项,则这是默认行为。
caseFirst 选项只影响仅大小写不同的字符串。对于基础字母不同的字符串,无论该设置如何,都会按照正常的字母顺序排序。
默认大小写顺序的工作原理
如果未指定 caseFirst 选项,排序器会根据语言环境和敏感度设置采用默认行为。
const collator = new Intl.Collator('en-US');
const words = ['apple', 'Apple', 'APPLE'];
words.sort(collator.compare);
console.log(words);
// Output: ['apple', 'Apple', 'APPLE']
输出顺序取决于具体实现和语言环境。在默认敏感度设置下,排序器会考虑大小写差异,但 apple、Apple 和 APPLE 的具体排序顺序会有所不同。
不同的语言环境有不同的默认大小写排序习惯。有些语言环境习惯将小写字母排在前面,而有些则将大写字母排在前面。依赖默认行为会导致在不同环境下结果不一致。
使用 caseFirst upper 将大写字母排在前面
设置 caseFirst: "upper" 可确保在排序结果中,大写字母始终排在其小写字母之前。
const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const words = ['apple', 'Apple', 'banana', 'Banana'];
words.sort(collator.compare);
console.log(words);
// Output: ['Apple', 'apple', 'Banana', 'banana']
排序器会先按基础字母进行字母顺序排序,然后在每组内应用大小写顺序。在以 a 开头的单词中,Apple 会排在 apple 之前。在以 b 开头的单词中,Banana 会排在 banana 之前。
这种排序方式在显示列表时非常有用,能够让专有名词或首字母大写的标题优先于普通名词显示,更加突出。
const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const names = ['smith', 'Smith', 'jones', 'Jones'];
names.sort(collator.compare);
console.log(names);
// Output: ['Jones', 'jones', 'Smith', 'smith']
首字母大写的名称会排在小写版本之前,有助于在混合列表中区分专有名词和普通词汇。
使用 caseFirst lower 让小写字母优先
设置 caseFirst: "lower" 可确保排序结果中小写字母始终排在其大写字母之前。
const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });
const words = ['apple', 'Apple', 'banana', 'Banana'];
words.sort(collator.compare);
console.log(words);
// Output: ['apple', 'Apple', 'banana', 'Banana']
排序器会先按字母顺序排列,然后在每个字母组内将小写字母排在大写字母之前。
这种排序方式符合某些约定,即小写文本被视为更标准或中性,而大写则用于强调或特殊情况。
const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });
const tags = ['javascript', 'JavaScript', 'python', 'Python'];
tags.sort(collator.compare);
console.log(tags);
// Output: ['javascript', 'JavaScript', 'python', 'Python']
小写标签会优先显示,这在小写代表规范形式、大写为不常见变体时非常有用。
使用 caseFirst false 采用本地默认行为
设置 caseFirst: "false"(字符串值)会显式请求使用本地的默认大小写排序方式。其结果与完全不设置该选项时相同。
const collator = new Intl.Collator('en-US', { caseFirst: 'false' });
const words = ['apple', 'Apple', 'APPLE'];
words.sort(collator.compare);
console.log(words);
// Output depends on locale implementation
输出顺序取决于本地的标准。有些本地习惯大写优先,有些则小写优先,还有些将大小写不同的字符串视为相等。
当你希望明确表示采用本地默认设置,而不是因遗漏配置而默认时,这个选项非常有用。
caseFirst 无效的情况
只有在敏感度设置允许区分大小写时,caseFirst 选项才会影响比较。如果使用 sensitivity: "base" 或 sensitivity: "accent",则完全忽略大小写差异,此时 caseFirst 选项无效。
const collator = new Intl.Collator('en-US', {
sensitivity: 'base',
caseFirst: 'upper'
});
const words = ['apple', 'Apple', 'APPLE'];
words.sort(collator.compare);
console.log(words);
// Output: ['apple', 'Apple', 'APPLE'] (or any order)
在基础敏感度下,collator 会将这三个字符串视为相等。由于大小写完全不被考虑,caseFirst 选项不会产生任何影响。排序算法会保留相等项的原始顺序(稳定排序),因此输出顺序与输入顺序一致。
要使 caseFirst 选项生效,请使用 sensitivity: "case" 或 sensitivity: "variant"(默认值)。
const collator = new Intl.Collator('en-US', {
sensitivity: 'variant',
caseFirst: 'upper'
});
const words = ['apple', 'Apple', 'APPLE'];
words.sort(collator.compare);
console.log(words);
// Output: ['APPLE', 'Apple', 'apple']
在 variant 敏感度下(会考虑所有差异,包括大小写),caseFirst 选项决定了这些大小写不同字符串的排序顺序。
按一致的大小写顺序排序名称
在对用户名或其他专有名词进行排序时,一致的大小写顺序可确保应用内结果的可预测性。
const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const users = [
{ name: 'alice' },
{ name: 'Alice' },
{ name: 'bob' },
{ name: 'Bob' }
];
users.sort((a, b) => collator.compare(a.name, b.name));
users.forEach(user => {
console.log(user.name);
});
// Output:
// Alice
// alice
// Bob
// bob
collator 会将首字母大写的名称排在小写版本之前。这种排序方式有助于在混合数据集中区分专有名词和普通词汇。
以受控大小写顺序排序文件名
文件系统的大小写敏感行为各不相同。有些将大写和小写视为相同,有些则区分。显式指定大小写顺序可确保无论底层文件系统如何,排序后的文件列表都能符合用户预期。
const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });
const files = ['README.md', 'readme.md', 'index.js', 'Index.js'];
files.sort(collator.compare);
console.log(files);
// Output: ['index.js', 'Index.js', 'readme.md', 'README.md']
小写版本会排在前面,这符合在类 Unix 系统中小写文件名更为常见的惯例。
结合 caseFirst 与数字排序
caseFirst 选项可与 numeric 等其他排序选项配合使用。你可以在控制大小写顺序的同时,对包含数字的字符串进行排序。
const collator = new Intl.Collator('en-US', {
numeric: true,
caseFirst: 'upper'
});
const items = ['item1', 'Item1', 'item2', 'Item2', 'item10', 'Item10'];
items.sort(collator.compare);
console.log(items);
// Output: ['Item1', 'item1', 'Item2', 'item2', 'Item10', 'item10']
collator 会对数字部分进行数值比较,对字母部分应用大小写排序。各项会先按数值(1、2、10)排序,再在每个数字组内按大小写排序。
使用 Unicode 扩展键设置 caseFirst
可以通过在区域标识符中使用 kf 键的 Unicode 扩展来设置 caseFirst 选项。扩展值包括 upper、lower 和 false。
const collator = new Intl.Collator('en-US-u-kf-upper');
const words = ['apple', 'Apple', 'banana', 'Banana'];
words.sort(collator.compare);
console.log(words);
// Output: ['Apple', 'apple', 'Banana', 'banana']
区域字符串 en-US-u-kf-upper 表示美式英语,并采用大写优先的排序方式。这与在选项对象中传递 { caseFirst: 'upper' } 的效果相同。
当 Unicode 扩展和选项对象都指定 caseFirst 时,以选项对象为准。
const collator = new Intl.Collator('en-US-u-kf-upper', {
caseFirst: 'lower'
});
const words = ['apple', 'Apple'];
words.sort(collator.compare);
console.log(words);
// Output: ['apple', 'Apple']
选项对象指定了 caseFirst: 'lower',这会覆盖区域字符串中的 kf-upper 扩展。此时,比较器将采用小写优先的排序方式。
检查比较器正在使用的 caseFirst 值
resolvedOptions() 方法会返回比较器实际使用的选项,包括 caseFirst 设置。
const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const options = collator.resolvedOptions();
console.log(options.caseFirst);
// Output: "upper"
这对于调试或验证比较器配置是否符合预期非常有用,尤其是在同时使用 Unicode 扩展和选项对象时。
const collator = new Intl.Collator('en-US-u-kf-lower');
const options = collator.resolvedOptions();
console.log(options.caseFirst);
// Output: "lower"
当没有选项对象覆盖时,已解析的选项会反映 Unicode 扩展的设置。
何时使用不同的 caseFirst 值
在以下情况下使用 caseFirst: "upper":
- 希望专有名词或标题排在普通单词前
- 应用约定将首字母大写文本视为更重要
- 排序时以大写形式为标准,例如人名
在以下情况下使用 caseFirst: "lower":
- 希望小写文本作为标准形式排在前面
- 应用约定将小写视为默认,大写为特殊
- 排序技术标识符时,小写更常见
在以下情况下使用 caseFirst: "false" :
- 你希望遵循特定语言环境的规范
- 你的应用对大小写不同的字符串顺序没有要求
- 你希望明确表示正在使用默认值,而不是因疏忽遗漏该选项