前言
最近遇到需求,要对版本号进行排序,分享下处理方法。
版本号规则介绍
版本号通常由三部分组成 MAJOR.MINOR.PATCH 既
主版本号.次版本号.修订号
方法1:按上面介绍的版本号规则我们可以按位置分别比较
代码如下
const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"];
versions.sort((a, b) => {
const [majorA, minorA, patchA] = a.split('.').map(Number);
const [majorB, minorB, patchB] = b.split('.').map(Number);
if (majorA !== majorB) {
return majorA - majorB;
}
if (minorA !== minorB) {
return minorA - minorB;
}
return patchA - patchB;
})
// ["1.2.3", "1.2.4", "1.2.10", "1.3.0", "1.10.2", "2.0.0"]
上面函数很好理解,就是按主版本号、次版本号、修订号顺序依次对比,然后返回值就可以了。
但是这种方法会有问题,版本号不一定都纯 数字化字符串。比如:'v1.1.1'这样的版本号也很常见,如果是这样的版本号,那上面的函数就不行了。
const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"].map(v => `v${v}`);
versions.sort((a, b) => {
const [majorA, minorA, patchA] = a.split('.').map(Number);
const [majorB, minorB, patchB] = b.split('.').map(Number);
if (majorA !== majorB) {
return majorA - majorB;
}
if (minorA !== minorB) {
return minorA - minorB;
}
return patchA - patchB;
})
// ['v1.2.3', 'v1.10.2', 'v1.2.4', 'v1.3.0', 'v2.0.0', 'v1.2.10']
从上面结果看,排序就乱了,当时你也可以把版本号中的v replace掉,然后在使用上面的函数也可以。
方法2: 使用localeCompare
localeCompare() 方法返回一个数字,表示参考字符串在排序顺序中是在给定字符串之前、之后还是与之相同
具体语法看MDN文件就可以了,这里简单说下版本号排序逻辑
const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"];
versions.sort((a, b) => {
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
})
//['1.2.3', '1.2.4', '1.2.10', '1.3.0', '1.10.2', '2.0.0']
再来看版本号前加上v后的结果
const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"].map(v => `v${v}`);
versions.sort((a, b) => {
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
})
//['v1.2.3', 'v1.2.4', 'v1.2.10', 'v1.3.0', 'v1.10.2', 'v2.0.0']
从结果上看,排序正常了
关于localeCompare第三个参数
这里的 localeCompare 使用了 { numeric: true, sensitivity: 'base' } 作为第三个参数,下面解释这两个属性:
1. numeric: true
numeric 选项用于数字感知比较。当设置为 true 时,localeCompare 会将字符串中的数字视为实际数值,而不是逐字符比较。这样可以确保版本号中的数字部分按照数值大小排序,而不是按字符串的字典顺序。对于字符串前面加v的情况,localeCompare 会先对字母部分进行比较。然后在处理numeric: true逻辑。
例如:
"v1.2.10"会排在"v1.10.2"之前,而不是"v1.2.3"。- 如果
numeric: false或没有指定,则"v1.10.2"会被认为小于"v1.2.10",因为字符 "1" 小于字符 "2"。
2. sensitivity: 'base'
sensitivity 选项决定了字符串比较的敏感度。base 表示在比较时忽略大小写和一些特殊字符的差异,只关注字母和数字的基本差异。
- 'base' :忽略大小写和字符的变音符号差异(例如 "a" 等同于 "A"、"ä" 等同于 "a")。
- 'accent' :区分变音符号,但忽略大小写(例如 "a" 不同于 "ä",但 "a" 等同于 "A")。
- 'case' :区分大小写,但忽略变音符号(例如 "a" 不同于 "A",但 "a" 等同于 "ä")。
- 'variant' :区分大小写和变音符号(例如 "a" 不同于 "ä" 也不同于 "A")。
总结
以上两种方法我认为localeCompare比较简单,当然这个函数功能非常的强大,有兴趣的可以看下MDN