如何实现含隐式数字的字母数字自然排序?(JavaScript)
自然排序(人类排序)的实现
这种能识别字符串中隐式/显式数字、符合人类直觉的排序方式叫做自然排序(也常称人类排序、字母数字排序),它区别于普通字典序排序——普通排序会把"Kane & Lynch 2..."中的"2"当作字符和":"比较,而自然排序会将数字视为数值,自动识别出"Kane & Lynch: Dead Men"隐含的序号1,让它排在带2的条目之前。
在JavaScript中可以轻松实现,推荐两种方式:
1. 使用原生Intl.Collator(推荐)
ES6及以上环境支持的原生API,性能优且支持多语言,只需开启numeric参数:
const titles = [ 'Kane & Lynch 2: Dog Days', 'Kane & Lynch: Dead Men', 'Grand Theft Auto V', 'Grand Theft Auto III' ]; // 初始化排序器,numeric: true开启数字数值比较 const naturalCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' // 忽略大小写和重音,可按需调整 }); // 执行排序 titles.sort(naturalCollator.compare); console.log(titles); // 输出顺序: // ["Kane & Lynch: Dead Men", "Kane & Lynch 2: Dog Days", "Grand Theft Auto III", "Grand Theft Auto V"]
2. 自定义排序函数(兼容老环境)
如果需要兼容ES6之前的环境,可以自己实现基于正则拆分的排序逻辑:
function naturalSort(a, b) { const numSplitRegex = /(\d+)/g; // 将字符串拆分为「非数字段+数字段」的数组,数字转数值,非数字转小写统一比较 const splitA = a.split(numSplitRegex).map(segment => isNaN(segment) ? segment.toLowerCase() : parseInt(segment, 10) ); const splitB = b.split(numSplitRegex).map(segment => isNaN(segment) ? segment.toLowerCase() : parseInt(segment, 10) ); // 逐个比较拆分后的片段 for (let i = 0; i < Math.max(splitA.length, splitB.length); i++) { const partA = splitA[i] ?? ''; const partB = splitB[i] ?? ''; if (partA !== partB) { // 数字比较数值大小,非数字用localeCompare做自然字符串比较 return typeof partA === 'number' ? partA - partB : partA.localeCompare(partB); } } return 0; } // 执行排序 titles.sort(naturalSort);
内容的提问来源于stack exchange,提问作者DonkeyLong
相关产品推荐
相关产品推荐

