以下是软件版本号:
"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"
我怎么比较呢?
假设正确的顺序是:
"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"
想法很简单…
读第一个数字,然后,第二个,第三个…
但是我不能将版本号转换为浮点数…
你也可以像这样看到版本号:
"1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1.0"
这样可以更清楚地看到背后的想法。
但是,我怎样才能把它转换成计算机程序呢?
这里有一个面向对象的有趣方法:
function versionString(str) {
var parts = str.split('.');
this.product = parts.length > 0 ? parts[0] * 1 : 0;
this.major = parts.length > 1 ? parts[1] * 1 : 0;
this.minor = parts.length > 2 ? parts[2] * 1 : 0;
this.build = parts.length > 3 ? parts[3] * 1 : 0;
this.compareTo = function(vStr){
vStr = this._isVersionString(vStr) ? vStr : new versionString(vStr);
return this.compare(this, vStr);
};
this.toString = function(){
return this.product + "." + this.major + "." + this.minor + "." + this.build;
}
this.compare = function (str1, str2) {
var vs1 = this._isVersionString(str1) ? str1 : new versionString(str1);
var vs2 = this._isVersionString(str2) ? str2 : new versionString(str2);
if (this._compareNumbers(vs1.product, vs2.product) == 0) {
if (this._compareNumbers(vs1.major, vs2.major) == 0) {
if (this._compareNumbers(vs1.minor, vs2.minor) == 0) {
return this._compareNumbers(vs1.build, vs2.build);
} else {
return this._compareNumbers(vs1.minor, vs2.minor);
}
} else {
return this._compareNumbers(vs1.major, vs2.major);
}
} else {
return this._compareNumbers(vs1.product, vs2.product);
}
};
this._isVersionString = function (str) {
return str !== undefined && str.build !== undefined;
};
this._compareNumbers = function (n1, n2) {
if (n1 > n2) {
return 1;
} else if (n1 < n2) {
return -1;
} else {
return 0;
}
};
}
还有一些测试:
var v1 = new versionString("1.0");
var v2 = new versionString("1.0.1");
var v3 = new versionString("2.0");
var v4 = new versionString("2.0.0.1");
var v5 = new versionString("2.0.1");
alert(v1.compareTo("1.4.2"));
alert(v3.compareTo(v1));
alert(v5.compareTo(v4));
alert(v4.compareTo(v5));
alert(v5.compareTo(v5));
这里找不到我想要的函数。所以我自己写了。这就是我的贡献。我希望有人觉得它有用。
优点:
处理任意长度的版本字符串。'1'或'1.1.1.1.1'。
如果没有指定,则默认为0。仅仅因为字符串更长并不意味着它是一个更大的版本。(“1”应与“1.0”和“1.0.0.0”相同。)
比较数字而不是字符串。('3'<'21'应为真。不是假的。)
不要把时间浪费在无用的比较上。(比较for ==)
你可以选择你自己的比较器。
缺点:
它不处理版本字符串中的字母。(我不知道这是怎么回事?)
我的代码,类似于Jon接受的答案:
function compareVersions(v1, comparator, v2) {
"use strict";
var comparator = comparator == '=' ? '==' : comparator;
if(['==','===','<','<=','>','>=','!=','!=='].indexOf(comparator) == -1) {
throw new Error('Invalid comparator. ' + comparator);
}
var v1parts = v1.split('.'), v2parts = v2.split('.');
var maxLen = Math.max(v1parts.length, v2parts.length);
var part1, part2;
var cmp = 0;
for(var i = 0; i < maxLen && !cmp; i++) {
part1 = parseInt(v1parts[i], 10) || 0;
part2 = parseInt(v2parts[i], 10) || 0;
if(part1 < part2)
cmp = 1;
if(part1 > part2)
cmp = -1;
}
return eval('0' + comparator + cmp);
}
例子:
compareVersions('1.2.0', '==', '1.2'); // true
compareVersions('00001', '==', '1.0.0'); // true
compareVersions('1.2.0', '<=', '1.2'); // true
compareVersions('2.2.0', '<=', '1.2'); // false
进行这种比较的基本思想是使用Array。拆分以从输入字符串中获得部件数组,然后比较两个数组中的部件对;如果部分不相等,我们就知道哪个版本更小。
这里有一些重要的细节需要记住:
每对零件应该如何比较?这个问题想要从数字上进行比较,但是如果我们有不只是由数字组成的版本字符串(例如。“1.0”)?
如果一个版本字符串的部分比另一个多,会发生什么?很可能“1.0”应该被认为小于“1.0.1”,但是“1.0.0”呢?
下面是你可以直接使用的实现代码(要点和文档):
function versionCompare(v1, v2, options) {
var lexicographical = options && options.lexicographical,
zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');
function isValidPart(x) {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
}
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length) v1parts.push("0");
while (v2parts.length < v1parts.length) v2parts.push("0");
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
if (v1parts[i] == v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length != v2parts.length) {
return -1;
}
return 0;
}
这个版本自然地比较各个部分,不接受字符后缀,并认为“1.7”比“1.7.0”小。比较模式可以更改为字典式,短版本字符串可以使用可选的第三个参数自动填充零。
这里有一个运行“单元测试”的JSFiddle;这是一个稍微扩展的版本的ripper234的工作(谢谢)。
重要提示:此代码使用Array。map和Array。这意味着它将不会在9之前的IE版本中运行。如果你需要支持这些方法,你就必须为缺失的方法提供填充。
虽然这个问题已经有很多答案,但每个人都在推广自己的解决方案,而我们有一个完整的生态系统(战斗)测试库。
在NPM, GitHub, X上快速搜索会给我们一些可爱的lib,我想要运行一些:
Semver-compare是一个很棒的轻量级库(约230字节),如果您想按版本号排序,它尤其有用,因为库的公开方法会适当地返回-1、0或1。
库的核心:
module.exports = function cmp (a, b) {
var pa = a.split('.');
var pb = b.split('.');
for (var i = 0; i < 3; i++) {
var na = Number(pa[i]);
var nb = Number(pb[i]);
if (na > nb) return 1;
if (nb > na) return -1;
if (!isNaN(na) && isNaN(nb)) return 1;
if (isNaN(na) && !isNaN(nb)) return -1;
}
return 0;
};
compare-semver的大小相当大(大约4.4 kB gzip),但是允许进行一些很好的惟一比较,比如查找一堆版本的最小/最大值,或者查找所提供的版本是惟一的还是比版本集合中的其他任何版本都小。
compare-versions是另一个小库(大约630字节gzip),它很好地遵循规范,这意味着你可以比较带有alpha/beta标志甚至通配符的版本(比如minor/patch版本:1.0)。X或1.0)
重点是:如果你能通过你选择的包管理器找到合适的(单元)测试版本,那么并不总是需要从Stack Overflow复制粘贴代码。
比较不同条件下的功能:
const compareVer = (ver1, middle, ver2) => {
const res = new Intl.Collator("en").compare(ver1, ver2)
let comp
switch (middle) {
case "=":
comp = 0 === res
break
case ">":
comp = 1 === res
break
case ">=":
comp = 1 === res || 0 === res
break
case "<":
comp = -1 === res
break
case "<=":
comp = -1 === res || 0 === res
break
}
return comp
}
console.log(compareVer("1.0.2", "=", "1.0.2")) // true
console.log(compareVer("1.0.3", ">", "1.0.2")) // true
console.log(compareVer("1.0.1", ">=", "1.0.2")) // false
console.log(compareVer("1.0.3", ">=", "1.0.2")) // true
console.log(compareVer("1.0.1", "<", "1.0.2")) // true
console.log(compareVer("1.0.1", "<=", "1.0.2")) // true