如何使用JavaScript比较软件版本号?数量(只)

以下是软件版本号:

"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"

这样可以更清楚地看到背后的想法是什么… 但是,我怎样才能把它转换成计算机程序呢?< / p >

138227 次浏览

你可以遍历每个以句点分隔的字符并将其转换为int类型:

var parts = versionString.split('.');


for (var i = 0; i < parts.length; i++) {
var value = parseInt(parts[i]);
// do stuffs here.. perhaps build a numeric version variable?
}

摘自http://java.com/js/deployJava.js:

    // return true if 'installed' (considered as a JRE version string) is
// greater than or equal to 'required' (again, a JRE version string).
compareVersions: function (installed, required) {


var a = installed.split('.');
var b = required.split('.');


for (var i = 0; i < a.length; ++i) {
a[i] = Number(a[i]);
}
for (var i = 0; i < b.length; ++i) {
b[i] = Number(b[i]);
}
if (a.length == 2) {
a[2] = 0;
}


if (a[0] > b[0]) return true;
if (a[0] < b[0]) return false;


if (a[1] > b[1]) return true;
if (a[1] < b[1]) return false;


if (a[2] > b[2]) return true;
if (a[2] < b[2]) return false;


return true;
}
// Return 1 if a > b
// Return -1 if a < b
// Return 0 if a == b
function compare(a, b) {
if (a === b) {
return 0;
}


var a_components = a.split(".");
var b_components = b.split(".");


var len = Math.min(a_components.length, b_components.length);


// loop while the components are equal
for (var i = 0; i < len; i++) {
// A bigger than B
if (parseInt(a_components[i]) > parseInt(b_components[i])) {
return 1;
}


// B bigger than A
if (parseInt(a_components[i]) < parseInt(b_components[i])) {
return -1;
}
}


// If one's a prefix of the other, the longer one is greater.
if (a_components.length > b_components.length) {
return 1;
}


if (a_components.length < b_components.length) {
return -1;
}


// Otherwise they are the same.
return 0;
}


console.log(compare("1", "2"));
console.log(compare("2", "1"));


console.log(compare("1.0", "1.0"));
console.log(compare("2.0", "1.0"));
console.log(compare("1.0", "2.0"));
console.log(compare("1.0.1", "1.0"));

进行这种比较的基本思想是使用Array.split从输入字符串中获取部件数组,然后比较两个数组中的部件对;如果部分不相等,我们就知道哪个版本更小。

这里有一些重要的细节需要记住:

  1. 每对零件应该如何比较?这个问题想要从数字上进行比较,但是如果我们有不只是由数字组成的版本字符串(例如。“1.0”)?
  2. 如果一个版本字符串的部分比另一个多,会发生什么?很可能“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.mapArray.every,这意味着它将不会在9之前的IE版本中运行。如果你需要支持这些方法,你就必须为缺失的方法提供填充。

replace()函数只替换字符串中的第一个出现项。因此,让我们用,替换.。然后删除所有.,并再次将,转换为.,并将其解析为float。

for(i=0; i<versions.length; i++) {
v = versions[i].replace('.', ',');
v = v.replace(/\./g, '');
versions[i] = parseFloat(v.replace(',', '.'));
}

最后,排序:

versions.sort();

检查函数php.js项目中的version_compare()。它类似于PHP 's  version_compare()

你可以像这样简单地使用它:

version_compare('2.0', '2.0.0.1', '<');
// returns true

你不能把它们转换成数字,然后按大小排序吗?在数字的1后面加上0 <长度为4

在主机上玩:

$(["1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1", "3.0"]).each(function(i,e) {
var n =   e.replace(/\./g,"");
while(n.length < 4) n+="0" ;
num.push(  +n  )
});

更大的版本,更大的数字。 编辑:可能需要调整以考虑更大的版本系列

这里有一个面向对象的有趣方法:

    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));

这实际上取决于你的版本控制系统背后的逻辑。每个数字代表什么,如何使用。

是否每个subversion都是一个用于指定开发阶段的数字? 为0 1代表β 发布候选2个 3(最终)发布

它是构建版本吗?您是否应用增量更新?

一旦了解了版本控制系统的工作原理,创建算法就变得很容易了。

如果您不允许在每个subversion中使用大于9的数字,则删除所有小数,但第一个小数将允许您进行直接比较。

如果允许在任何一种颠覆版本中使用大于9的数字,有几种方法可以比较它们。最明显的方法是将字符串按小数分割,然后比较每一列。

但是在不知道版本控制系统是如何工作的情况下,当版本1.0.2a发布时,实现像上面这样的过程可能会很麻烦。

看看这个博客。此函数适用于数字版本号。

function compVersions(strV1, strV2) {
var nRes = 0
, parts1 = strV1.split('.')
, parts2 = strV2.split('.')
, nLen = Math.max(parts1.length, parts2.length);


for (var i = 0; i < nLen; i++) {
var nP1 = (i < parts1.length) ? parseInt(parts1[i], 10) : 0
, nP2 = (i < parts2.length) ? parseInt(parts2[i], 10) : 0;


if (isNaN(nP1)) { nP1 = 0; }
if (isNaN(nP2)) { nP2 = 0; }


if (nP1 != nP2) {
nRes = (nP1 > nP2) ? 1 : -1;
break;
}
}


return nRes;
};


compVersions('10', '10.0'); // 0
compVersions('10.1', '10.01.0'); // 0
compVersions('10.0.1', '10.0'); // 1
compVersions('10.0.1', '10.1'); // -1
例如,如果我们想检查当前jQuery版本是否小于1.8,如果version为"1.10.1",parseFloat($.ui.version) < 1.8 )将返回错误的结果,因为parseFloat("1.10.1")返回1.1。 字符串比较也会出错,因为"1.8" < "1.10"的结果是false.

所以我们需要一个这样的测试

if(versionCompare($.ui.version, "1.8") < 0){
alert("please update jQuery");
}

下面的函数可以正确地处理这个问题:

/** Compare two dotted version strings (like '10.2.3').
* @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2
*/
function versionCompare(v1, v2) {
var v1parts = ("" + v1).split("."),
v2parts = ("" + v2).split("."),
minLength = Math.min(v1parts.length, v2parts.length),
p1, p2, i;
// Compare tuple pair-by-pair.
for(i = 0; i < minLength; i++) {
// Convert to integer if possible, because "8" > "10".
p1 = parseInt(v1parts[i], 10);
p2 = parseInt(v2parts[i], 10);
if (isNaN(p1)){ p1 = v1parts[i]; }
if (isNaN(p2)){ p2 = v2parts[i]; }
if (p1 == p2) {
continue;
}else if (p1 > p2) {
return 1;
}else if (p1 < p2) {
return -1;
}
// one operand is NaN
return NaN;
}
// The longer tuple is always considered 'greater'
if (v1parts.length === v2parts.length) {
return 0;
}
return (v1parts.length < v2parts.length) ? -1 : 1;
}

下面是一些例子:

// compare dotted version strings
console.assert(versionCompare("1.8",      "1.8.1")    <   0);
console.assert(versionCompare("1.8.3",    "1.8.1")    >   0);
console.assert(versionCompare("1.8",      "1.10")     <   0);
console.assert(versionCompare("1.10.1",   "1.10.1")   === 0);
// Longer is considered 'greater'
console.assert(versionCompare("1.10.1.0", "1.10.1")   >   0);
console.assert(versionCompare("1.10.1",   "1.10.1.0") <   0);
// Strings pairs are accepted
console.assert(versionCompare("1.x",      "1.x")      === 0);
// Mixed int/string pairs return NaN
console.assert(isNaN(versionCompare("1.8", "1.x")));
//works with plain numbers
console.assert(versionCompare("4", 3)   >   0);

看到这里的现场样本和测试套件: http://jsfiddle.net/mar10/8KjvP/ < / p >

这个非常小,但非常快的比较函数需要任何长度的版本号每段的任意数字大小

< p >返回值:< br > -一个数字< 0如果一个<b < br > -如果> b
,则返回数字> 0 - 0如果a = b

所以你可以使用它作为比较Array.sort()的函数;

编辑:修正了版本剥离后面的零来识别“1”和“1.0.0”相等的错误

function cmpVersions (a, b) {
var i, diff;
var regExStrip0 = /(\.0+)+$/;
var segmentsA = a.replace(regExStrip0, '').split('.');
var segmentsB = b.replace(regExStrip0, '').split('.');
var l = Math.min(segmentsA.length, segmentsB.length);


for (i = 0; i < l; i++) {
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
if (diff) {
return diff;
}
}
return segmentsA.length - segmentsB.length;
}


// TEST
console.log(
['2.5.10.4159',
'1.0.0',
'0.5',
'0.4.1',
'1',
'1.1',
'0.0.0',
'2.5.0',
'2',
'0.0',
'2.5.10',
'10.5',
'1.25.4',
'1.2.15'].sort(cmpVersions));
// Result:
// ["0.0.0", "0.0", "0.4.1", "0.5", "1.0.0", "1", "1.1", "1.2.15", "1.25.4", "2", "2.5.0", "2.5.10", "2.5.10.4159", "10.5"]

这是一个巧妙的技巧。如果您正在处理数值,在特定的值范围内,您可以为版本对象的每个级别分配一个值。例如,“largestValue”在这里被设置为0xFF,这为您的版本控制创建了一个非常“IP”的外观。

这也处理字母数字版本(即1.2a <1.2 b)

// The version compare function
function compareVersion(data0, data1, levels) {
function getVersionHash(version) {
var value = 0;
version = version.split(".").map(function (a) {
var n = parseInt(a);
var letter = a.replace(n, "");
if (letter) {
return n + letter[0].charCodeAt() / 0xFF;
} else {
return n;
}
});
for (var i = 0; i < version.length; ++i) {
if (levels === i) break;
value += version[i] / 0xFF * Math.pow(0xFF, levels - i + 1);
}
return value;
};
var v1 = getVersionHash(data0);
var v2 = getVersionHash(data1);
return v1 === v2 ? -1 : v1 > v2 ? 0 : 1;
};
// Returns 0 or 1, correlating to input A and input B
// Direct match returns -1
var version = compareVersion("1.254.253", "1.254.253a", 3);

我喜欢的版本来自@mar10,尽管从我的角度来看,有误用的机会(如果版本与语义版本控制文档兼容,似乎不是这样,但如果使用了一些“构建号”,则可能是这样):

versionCompare( '1.09', '1.1');  // returns 1, which is wrong:  1.09 < 1.1
versionCompare('1.702', '1.8');  // returns 1, which is wrong: 1.702 < 1.8

这里的问题是,在某些情况下,版本号的子数字被删除了后面的零(至少我最近在使用不同的软件时看到的),这类似于数字的有理数部分,因此:

5.17.2054 > 5.17.2
5.17.2 == 5.17.20 == 5.17.200 == ...
5.17.2054 > 5.17.20
5.17.2054 > 5.17.200
5.17.2054 > 5.17.2000
5.17.2054 > 5.17.20000
5.17.2054 < 5.17.20001
5.17.2054 < 5.17.3
5.17.2054 < 5.17.30

但是,第一个(或第一个和第二个)版本子号始终被视为它实际等于的整数值。

如果你使用这种版本控制,你可以只改变例子中的几行:

// replace this:
p1 = parseInt(v1parts[i], 10);
p2 = parseInt(v2parts[i], 10);
// with this:
p1 = i/* > 0 */ ? parseFloat('0.' + v1parts[i], 10) : parseInt(v1parts[i], 10);
p2 = i/* > 0 */ ? parseFloat('0.' + v2parts[i], 10) : parseInt(v2parts[i], 10);

因此,除了第一个子数字外,每个子数字都将作为浮点数进行比较,因此091将相应地变成0.090.1,并以这种方式正确地进行比较。20543将变成0.20540.3

那么完整的版本是(credit to @mar10):

/** Compare two dotted version strings (like '10.2.3').
* @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2
*/
function versionCompare(v1, v2) {
var v1parts = ("" + v1).split("."),
v2parts = ("" + v2).split("."),
minLength = Math.min(v1parts.length, v2parts.length),
p1, p2, i;
// Compare tuple pair-by-pair.
for(i = 0; i < minLength; i++) {
// Convert to integer if possible, because "8" > "10".
p1 = i/* > 0 */ ? parseFloat('0.' + v1parts[i], 10) : parseInt(v1parts[i], 10);;
p2 = i/* > 0 */ ? parseFloat('0.' + v2parts[i], 10) : parseInt(v2parts[i], 10);
if (isNaN(p1)){ p1 = v1parts[i]; }
if (isNaN(p2)){ p2 = v2parts[i]; }
if (p1 == p2) {
continue;
}else if (p1 > p2) {
return 1;
}else if (p1 < p2) {
return -1;
}
// one operand is NaN
return NaN;
}
// The longer tuple is always considered 'greater'
if (v1parts.length === v2parts.length) {
return 0;
}
return (v1parts.length < v2parts.length) ? -1 : 1;
}

注:这是比较慢的,但也可以考虑重用相同的比较函数来操作字符串实际上是字符数组的事实:

 function cmp_ver(arr1, arr2) {
// fill the tail of the array with smaller length with zeroes, to make both array have the same length
while (min_arr.length < max_arr.length) {
min_arr[min_arr.lentgh] = '0';
}
// compare every element in arr1 with corresponding element from arr2,
// but pass them into the same function, so string '2054' will act as
// ['2','0','5','4'] and string '19', in this case, will become ['1', '9', '0', '0']
for (i: 0 -> max_length) {
var res = cmp_ver(arr1[i], arr2[i]);
if (res !== 0) return res;
}
}

我根据Kons的想法做了这个,并针对Java版本“1.7.0_45”进行了优化。它只是一个将版本字符串转换为浮点数的函数。这是函数:

function parseVersionFloat(versionString) {
var versionArray = ("" + versionString)
.replace("_", ".")
.replace(/[^0-9.]/g, "")
.split("."),
sum = 0;
for (var i = 0; i < versionArray.length; ++i) {
sum += Number(versionArray[i]) / Math.pow(10, i * 3);
}
console.log(versionString + " -> " + sum);
return sum;
}

字符串“1.7.0_45”被转换为1.0070000450000001,这足以进行正常的比较。错误解释在这里:如何处理JavaScript中的浮点数精度?。如果需要任何部分多于3位数字,您可以更改除法器Math.pow(10, i * 3);

输出如下所示:

1.7.0_45         > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890    > 1.23456789

这里找不到我想要的函数。所以我自己写了。这就是我的贡献。我希望有人觉得它有用。

优点:

  • 处理任意长度的版本字符串。'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使用的coffeescript实现。从其他答案中得到启发:

# Returns > 0 if v1 > v2 and < 0 if v1 < v2 and 0 if v1 == v2
compareVersions = (v1, v2) ->
v1Parts = v1.split('.')
v2Parts = v2.split('.')
minLength = Math.min(v1Parts.length, v2Parts.length)
if minLength > 0
for idx in [0..minLength - 1]
diff = Number(v1Parts[idx]) - Number(v2Parts[idx])
return diff unless diff is 0
return v1Parts.length - v2Parts.length

我写了一个排序版本的节点模块,你可以在这里找到它:version-sort

特性:

  • 序列“1.0.1.5.53.54654.114.1.154.45”不受限制
  • 不限制序列长度:'1.1546515465451654654654654138754431574364321353734'工作
  • 可以根据版本对对象进行排序(参见README)
  • 阶段(如alpha, beta, rc1, rc2)

如果您需要其他功能,请不要犹豫,打开一个问题。

这不是一个很好的解决问题的方法,但它非常相似。

这个排序函数是针对语义版本的,它处理已解析的版本,所以它不能处理像x*这样的通配符。

它适用于匹配此正则表达式的版本:/\d+\.\d+\.\d+.*$/。它非常类似于这个答案,除了它也适用于像1.2.3-dev这样的版本。 在与其他答案的比较中:我删除了一些我不需要的检查,但我的解决方案可以与另一个相结合
semVerSort = function(v1, v2) {
var v1Array = v1.split('.');
var v2Array = v2.split('.');
for (var i=0; i<v1Array.length; ++i) {
var a = v1Array[i];
var b = v2Array[i];
var aInt = parseInt(a, 10);
var bInt = parseInt(b, 10);
if (aInt === bInt) {
var aLex = a.substr((""+aInt).length);
var bLex = b.substr((""+bInt).length);
if (aLex === '' && bLex !== '') return 1;
if (aLex !== '' && bLex === '') return -1;
if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1;
continue;
} else if (aInt > bInt) {
return 1;
} else {
return -1;
}
}
return 0;
}

合并后的解为:

function versionCompare(v1, v2, options) {
var zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');


if (zeroExtend) {
while (v1parts.length < v2parts.length) v1parts.push("0");
while (v2parts.length < v1parts.length) v2parts.push("0");
}


for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
var v1Int = parseInt(v1parts[i], 10);
var v2Int = parseInt(v2parts[i], 10);
if (v1Int == v2Int) {
var v1Lex = v1parts[i].substr((""+v1Int).length);
var v2Lex = v2parts[i].substr((""+v2Int).length);
if (v1Lex === '' && v2Lex !== '') return 1;
if (v1Lex !== '' && v2Lex === '') return -1;
if (v1Lex !== '' && v2Lex !== '') return v1Lex > v2Lex ? 1 : -1;
continue;
}
else if (v1Int > v2Int) {
return 1;
}
else {
return -1;
}
}


if (v1parts.length != v2parts.length) {
return -1;
}


return 0;
}

我也遇到了版本比较的问题,但是版本可能包含任何内容(例如:不是点的分隔符,像rc1, rc2…)

我使用了这个方法,它基本上将版本字符串分为数字和非数字,并尝试根据类型进行比较。

function versionCompare(a,b) {
av = a.match(/([0-9]+|[^0-9]+)/g)
bv = b.match(/([0-9]+|[^0-9]+)/g)
for (;;) {
ia = av.shift();
ib = bv.shift();
if ( (typeof ia === 'undefined') && (typeof ib === 'undefined') ) { return 0; }
if (typeof ia === 'undefined') { ia = '' }
if (typeof ib === 'undefined') { ib = '' }


ian = parseInt(ia);
ibn = parseInt(ib);
if ( isNaN(ian) || isNaN(ibn) ) {
// non-numeric comparison
if (ia < ib) { return -1;}
if (ia > ib) { return 1;}
} else {
if (ian < ibn) { return -1;}
if (ian > ibn) { return 1;}
}
}
}

对于某些情况,这里有一些假设,例如:“1.01”===“1.1”,或“1.8”<“1.71”。它无法管理“1.0.0-rc”。1”& lt;“1.0.0”,由语义版本2.0.0指定

function versionCompare(version1, version2){
var a = version1.split('.');
var b = version2.split('.');
for (var i = 0; i < a.length; ++i) {
a[i] = Number(a[i]);
}
for (var i = 0; i < b.length; ++i) {
b[i] = Number(b[i]);
}
var length=a.length;


for(j=0; j<length; j++){
if(typeof b[j]=='undefined')b[j]=0;
if (a[j] > b[j]) return true;
else if(a[j] < b[j])return false;
if(j==length-1 && a[j] >= b[j])return true;
}


return false;
},

semver

npm使用的语义版本解析器。

$ npm install semver
var semver = require('semver');


semver.diff('3.4.5', '4.3.7') //'major'
semver.diff('3.4.5', '3.3.7') //'minor'
semver.gte('3.4.8', '3.4.7') //true
semver.ltr('3.4.8', '3.4.7') //false


semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
semver.clean(' =v1.2.3 ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true


var versions = [ '1.2.3', '3.4.5', '1.0.2' ]
var max = versions.sort(semver.rcompare)[0]
var min = versions.sort(semver.compare)[0]
var max = semver.maxSatisfying(versions, '*')

语义版本链接:
https://www.npmjs.com/package/semver#prerelease-identifiers

在排序之前对版本进行预处理意味着parseInt不会被不必要地多次调用。 使用array# map类似于Michael Deal的建议,下面是我用来查找标准3部分semver的最新版本的排序:

.
var semvers = ["0.1.0", "1.0.0", "1.1.0", "1.0.5"];


var versions = semvers.map(function(semver) {
return semver.split(".").map(function(part) {
return parseInt(part);
});
});


versions.sort(function(a, b) {
if (a[0] < b[0]) return 1;
else if (a[0] > b[0]) return -1;
else if (a[1] < b[1]) return 1;
else if (a[1] > b[1]) return -1;
else if (a[2] < b[2]) return 1;
else if (a[2] > b[2]) return -1;
return 0;
});


var newest = versions[0].join(".");
console.log(newest); // "1.1.0"

我认为这是一个值得分享的实现,因为它简短,简单,但功能强大。请注意,它只使用数字比较。通常它会检查version2是否比version1晚,如果是,则返回true。假设您有version1: 1.1.1和version2: 1.1.2。它遍历两个版本的每个部分,将它们的部分相加如下:对于版本1(1 + 0.1)然后(1.1 + 0.01),对于版本2(1 + 0.1)然后(1.1 + 0.02)。

function compareVersions(version1, version2) {


version1 = version1.split('.');
version2 = version2.split('.');


var maxSubVersionLength = String(Math.max.apply(undefined, version1.concat(version2))).length;


var reduce = function(prev, current, index) {


return parseFloat(prev) + parseFloat('0.' + Array(index + (maxSubVersionLength - String(current).length)).join('0') + current);
};


return version1.reduce(reduce) < version2.reduce(reduce);
}

如果你想从版本列表中找到最新的版本,那么这可能是有用的:

function findLatestVersion(versions) {


if (!(versions instanceof Array)) {
versions = Array.prototype.slice.apply(arguments, [0]);
}


versions = versions.map(function(version) { return version.split('.'); });


var maxSubVersionLength = String(Math.max.apply(undefined, Array.prototype.concat.apply([], versions))).length;


var reduce = function(prev, current, index) {


return parseFloat(prev) + parseFloat('0.' + Array(index + (maxSubVersionLength - String(current).length)).join('0') + current);
};


var sums = [];


for (var i = 0; i < versions.length; i++) {
sums.push(parseFloat(versions[i].reduce(reduce)));
}


return versions[sums.indexOf(Math.max.apply(undefined, sums))].join('.');
}


console.log(findLatestVersion('0.1000000.1', '2.0.0.10', '1.6.10', '1.4.3', '2', '2.0.0.1')); // 2.0.0.10
console.log(findLatestVersion(['0.1000000.1', '2.0.0.10', '1.6.10', '1.4.3', '2', '2.0.0.1'])); // 2.0.0.10

原谅我,如果这个想法已经访问在一个链接我没有看到。

我已经有了一些成功的部分转换成一个加权和像这样:

partSum = this.major * Math.Pow(10,9);
partSum += this.minor * Math.Pow(10, 6);
partSum += this.revision * Math.Pow(10, 3);
partSum += this.build * Math.Pow(10, 0);
这使得比较非常容易(比较double)。 我们的版本字段永远不会超过4位
7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0

我希望这能帮助到一些人,因为多重条件句似乎有点过度。

这适用于由句点分隔的任何长度的数字版本。只有当myVersion为>= minimumVersion时,它才返回true,假设版本1小于1.0,版本1.1小于1.1.0,以此类推。添加额外的条件应该相当简单,比如接受数字(只需转换为字符串)和十六进制,或者使分隔符动态(只需添加一个分隔符参数,然后将“。”替换为参数)

function versionCompare(myVersion, minimumVersion) {


var v1 = myVersion.split("."), v2 = minimumVersion.split("."), minLength;


minLength= Math.min(v1.length, v2.length);


for(i=0; i<minLength; i++) {
if(Number(v1[i]) > Number(v2[i])) {
return true;
}
if(Number(v1[i]) < Number(v2[i])) {
return false;
}
}


return (v1.length >= v2.length);
}

下面是一些测试:

console.log(versionCompare("4.4.0","4.4.1"));
console.log(versionCompare("5.24","5.2"));
console.log(versionCompare("4.1","4.1.2"));
console.log(versionCompare("4.1.2","4.1"));
console.log(versionCompare("4.4.4.4","4.4.4.4.4"));
console.log(versionCompare("4.4.4.4.4.4","4.4.4.4.4"));
console.log(versionCompare("0","1"));
console.log(versionCompare("1","1"));
console.log(versionCompare("","1"));
console.log(versionCompare("10.0.1","10.1"));

这里有一个递归版本

function versionCompare(myVersion, minimumVersion) {
return recursiveCompare(myVersion.split("."),minimumVersion.split("."),Math.min(myVersion.length, minimumVersion.length),0);
}


function recursiveCompare(v1, v2,minLength, index) {
if(Number(v1[index]) < Number(v2[index])) {
return false;
}
if(Number(v1[i]) < Number(v2[i])) {
return true;
}
if(index === minLength) {
return (v1.length >= v2.length);
}
return recursiveCompare(v1,v2,minLength,index+1);
}

这是另一种递归算法。

这段代码只使用了Array。shift和递归,这意味着它可以在Internet Explorer 6+中运行。如果你有任何疑问,你可以访问我的GitHub页面

(function(root, factory) {
if (typeof exports === 'object') {
return module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
return define(factory);
} else {
return root.compareVer = factory();
}
})(this, function() {
'use strict';
var _compareVer;
_compareVer = function(newVer, oldVer) {
var VER_RE, compareNum, isTrue, maxLen, newArr, newLen, newMatch, oldArr, oldLen, oldMatch, zerofill;
VER_RE = /(\d+\.){1,9}\d+/;
if (arguments.length !== 2) {
return -100;
}
if (typeof newVer !== 'string') {
return -2;
}
if (typeof oldVer !== 'string') {
return -3;
}
newMatch = newVer.match(VER_RE);
if (!newMatch || newMatch[0] !== newVer) {
return -4;
}
oldMatch = oldVer.match(VER_RE);
if (!oldMatch || oldMatch[0] !== oldVer) {
return -5;
}
newVer = newVer.replace(/^0/, '');
oldVer = oldVer.replace(/^0/, '');
if (newVer === oldVer) {
return 0;
} else {
newArr = newVer.split('.');
oldArr = oldVer.split('.');
newLen = newArr.length;
oldLen = oldArr.length;
maxLen = Math.max(newLen, oldLen);
zerofill = function() {
newArr.length < maxLen && newArr.push('0');
oldArr.length < maxLen && oldArr.push('0');
return newArr.length !== oldArr.length && zerofill();
};
newLen !== oldLen && zerofill();
if (newArr.toString() === oldArr.toString()) {
if (newLen > oldLen) {
return 1;
} else {
return -1;
}
} else {
isTrue = -1;
compareNum = function() {
var _new, _old;
_new = ~~newArr.shift();
_old = ~~oldArr.shift();
_new > _old && (isTrue = 1);
return _new === _old && newArr.length > 0 && compareNum();
};
compareNum();
return isTrue;
}
}
};
return _compareVer;
});

好吧,我希望这段代码能帮助到一些人。

下面是测试。

console.log(compareVer("0.0.2","0.0.1"));//1
console.log(compareVer("0.0.10","0.0.1")); //1
console.log(compareVer("0.0.10","0.0.2")); //1
console.log(compareVer("0.9.0","0.9")); //1
console.log(compareVer("0.10.0","0.9.0")); //1
console.log(compareVer("1.7", "1.07")); //1
console.log(compareVer("1.0.07", "1.0.007")); //1


console.log(compareVer("0.3","0.3")); //0
console.log(compareVer("0.0.3","0.0.3")); //0
console.log(compareVer("0.0.3.0","0.0.3.0")); //0
console.log(compareVer("00.3","0.3")); //0
console.log(compareVer("00.3","00.3")); //0
console.log(compareVer("01.0.3","1.0.3")); //0
console.log(compareVer("1.0.3","01.0.3")); //0


console.log(compareVer("0.2.0","1.0.0")); //-1
console.log(compareVer('0.0.2.2.0',"0.0.2.3")); //-1
console.log(compareVer('0.0.2.0',"0.0.2")); //-1
console.log(compareVer('0.0.2',"0.0.2.0")); //-1
console.log(compareVer("1.07", "1.7")); //-1
console.log(compareVer("1.0.007", "1.0.07")); //-1


console.log(compareVer()); //-100
console.log(compareVer("0.0.2")); //-100
console.log(compareVer("0.0.2","0.0.2","0.0.2")); //-100
console.log(compareVer(1212,"0.0.2")); //-2
console.log(compareVer("0.0.2",1212)); //-3
console.log(compareVer('1.abc.2',"1.0.2")); //-4
console.log(compareVer('1.0.2',"1.abc.2")); //-5

我们的想法是比较两个版本,并知道哪个是最大的。我们删除“;”;我们比较向量的每个位置。

// Return 1  if a > b
// Return -1 if a < b
// Return 0  if a == b


function compareVersions(a_components, b_components) {


if (a_components === b_components) {
return 0;
}


var partsNumberA = a_components.split(".");
var partsNumberB = b_components.split(".");


for (var i = 0; i < partsNumberA.length; i++) {


var valueA = parseInt(partsNumberA[i]);
var valueB = parseInt(partsNumberB[i]);


// A bigger than B
if (valueA > valueB || isNaN(valueB)) {
return 1;
}


// B bigger than A
if (valueA < valueB) {
return -1;
}
}
}

我找到了最简单的方法来比较它们,但我不确定这是否是你想要的。

当我在控制台中运行下面的代码时,它是有意义的,并且使用sort()方法,我可以获得版本字符串的排序数组。它是根据字母顺序排列的。

"1.0" < "1.0.1" //true
var arr = ["1.0.1", "1.0", "3.2.0", "1.3"]
arr.sort();     //["1.0", "1.0.1", "1.3", "3.2.0"]

下面是一个版本,它对版本字符串进行排序,而不分配任何子字符串或数组。由于它分配的对象更少,GC要做的工作也就更少。

有一对分配(以允许重用getVersionPart方法),但如果您对性能非常敏感,则可以扩展它以完全避免分配。

const compareVersionStrings : (a: string, b: string) => number = (a, b) =>
{
var ia = {s:a,i:0}, ib = {s:b,i:0};
while (true)
{
var na = getVersionPart(ia), nb = getVersionPart(ib);


if (na === null && nb === null)
return 0;
if (na === null)
return -1;
if (nb === null)
return 1;
if (na > nb)
return 1;
if (na < nb)
return -1;
}
};


const zeroCharCode = '0'.charCodeAt(0);


const getVersionPart = (a : {s:string, i:number}) =>
{
if (a.i >= a.s.length)
return null;


var n = 0;
while (a.i < a.s.length)
{
if (a.s[a.i] === '.')
{
a.i++;
break;
}


n *= 10;
n += a.s.charCodeAt(a.i) - zeroCharCode;
a.i++;
}
return n;
}

2017答:

v1 = '20.0.12';
v2 = '3.123.12';


compareVersions(v1,v2)
// return positive: v1 > v2, zero:v1 == v2, negative: v1 < v2
function compareVersions(v1, v2) {
v1= v1.split('.')
v2= v2.split('.')
var len = Math.max(v1.length,v2.length)
/*default is true*/
for( let i=0; i < len; i++)
v1 = Number(v1[i] || 0);
v2 = Number(v2[i] || 0);
if (v1 !== v2) return v1 - v2 ;
i++;
}
return 0;
}

最简单的现代浏览器代码:

 function compareVersion2(ver1, ver2) {
ver1 = ver1.split('.').map( s => s.padStart(10) ).join('.');
ver2 = ver2.split('.').map( s => s.padStart(10) ).join('.');
return ver1 <= ver2;
}

这里的想法是比较数字,但以字符串的形式。为了使比较工作,两个字符串必须在相同的长度。所以:

"123" > "99"变成"123" > "099"
填充短数字“修复”比较

这里我用0填充每个部分,长度为10。然后使用简单的字符串比较来得到答案

例子:

var ver1 = '0.2.10', ver2=`0.10.2`
//become
ver1 = '0000000000.0000000002.0000000010'
ver2 = '0000000000.0000000010.0000000002'
// then it easy to see that
ver1 <= ver2 // true
// Returns true if v1 is bigger than v2, and false if otherwise.
function isNewerThan(v1, v2) {
v1=v1.split('.');
v2=v2.split('.');
for(var i = 0; i<Math.max(v1.length,v2.length); i++){
if(v1[i] == undefined) return false; // If there is no digit, v2 is automatically bigger
if(v2[i] == undefined) return true; // if there is no digit, v1 is automatically bigger
if(v1[i] > v2[i]) return true;
if(v1[i] < v2[i]) return false;
}
return false; // Returns false if they are equal
}

功能简单简短:

function isNewerVersion (oldVer, newVer) {
const oldParts = oldVer.split('.')
const newParts = newVer.split('.')
for (var i = 0; i < newParts.length; i++) {
const a = ~~newParts[i] // parse int
const b = ~~oldParts[i] // parse int
if (a > b) return true
if (a < b) return false
}
return false
}

测试:

isNewerVersion('1.0', '2.0') // true
isNewerVersion('1.0', '1.0.1') // true
isNewerVersion('1.0.1', '1.0.10') // true
isNewerVersion('1.0.1', '1.0.1') // false
isNewerVersion('2.0', '1.0') // false
isNewerVersion('2', '1.0') // false
isNewerVersion('2.0.0.0.0.1', '2.1') // true
isNewerVersion('2.0.0.0.0.1', '2.0') // false

这是我的解。它已经在leetcode上被接受。我在今天的面试中遇到了问题。但我当时没有解决它。 我又想了想。加0使两个数组的长度相等。然后比较。< / p >

var compareVersion = function(version1, version2) {
let arr1 = version1.split('.').map(Number);
let arr2 = version2.split('.').map(Number);
let diff = 0;
if (arr1.length > arr2.length){
diff = arr1.length - arr2.length;
while (diff > 0){
arr2.push(0);
diff--;
}
}
else if (arr1.length < arr2.length){
diff = arr2.length - arr1.length;
while (diff > 0){
arr1.push(0);
diff--;
}
}
   

let i = 0;
while (i < arr1.length){
if (arr1[i] > arr2[i]){
return 1;
} else if (arr1[i] < arr2[i]){
return -1;
}
i++;
}
return 0;
    

};

下面是另一个简短的版本,适用于任何数量的子版本,填充零和偶数字母(1.0.0b3)

const compareVer = ((prep, repl) =>
{
prep = t => ("" + t)
//treat non-numerical characters as lower version
//replacing them with a negative number based on charcode of first character
.replace(/[^0-9\.]+/g, c => "." + (c.replace(/[\W_]+/, "").toLowerCase().charCodeAt(0) - 65536) + ".")
//remove trailing "." and "0" if followed by non-numerical characters (1.0.0b);
.replace(/(?:\.0+)*(\.-[0-9]+)(\.[0-9]+)?\.*$/g, "$1$2")
.split('.');


return (a, b, c, i, r) =>
{
a = prep(a);
b = prep(b);
for (i = 0, r = 0, c = Math.max(a.length, b.length); !r && i++ < c;)
{
r = -1 * ((a[i] = ~~a[i]) < (b[i] = ~~b[i])) + (a[i] > b[i]);
}
return r;
}
})();

函数返回:

如果a = b . 0

如果a > b . 1

如果a < b . -1

1.0         = 1.0.0.0.0.0
1.0         < 1.0.1
1.0b1       < 1.0
1.0b        = 1.0b
1.1         > 1.0.1b
1.1alpha    < 1.1beta
1.1rc1      > 1.1beta
1.1rc1      < 1.1rc2
1.1.0a1     < 1.1a2
1.1.0a10    > 1.1.0a1
1.1.0alpha  = 1.1a
1.1.0alpha2 < 1.1b1
1.0001      > 1.00000.1.0.0.0.01

/*use strict*/
const compareVer = ((prep, repl) =>
{
prep = t => ("" + t)
//treat non-numerical characters as lower version
//replacing them with a negative number based on charcode of first character
.replace(/[^0-9\.]+/g, c => "." + (c.replace(/[\W_]+/, "").toLowerCase().charCodeAt(0) - 65536) + ".")
//remove trailing "." and "0" if followed by non-numerical characters (1.0.0b);
.replace(/(?:\.0+)*(\.-[0-9]+)(\.[0-9]+)?\.*$/g, "$1$2")
.split('.');


return (a, b, c, i, r) =>
{
a = prep(a);
b = prep(b);
for (i = 0, r = 0, c = Math.max(a.length, b.length); !r && i++ < c;)
{
r = -1 * ((a[i] = ~~a[i]) < (b[i] = ~~b[i])) + (a[i] > b[i]);
}
return r;
}
})();


//examples


let list = [
["1.0",         "1.0.0.0.0.0"],
["1.0",         "1.0.1"],
["1.0b1",       "1.0"],
["1.0b",        "1.0b"],
["1.1",         "1.0.1b"],
["1.1alpha",    "1.1beta"],
["1.1rc1",      "1.1beta"],
["1.1rc1",      "1.1rc2"],
["1.1.0a1",     "1.1a2"],
["1.1.0a10",    "1.1.0a1"],
["1.1.0alpha",  "1.1a"],
["1.1.0alpha2", "1.1b1"],
["1.0001",      "1.00000.1.0.0.0.01"]
]
for(let i = 0; i < list.length; i++)
{
console.log( list[i][0] + " " + "<=>"[compareVer(list[i][0], list[i][1]) + 1] + " " + list[i][1] );
}

https://jsfiddle.net/vanowm/p7uvtbor/

虽然这个问题已经有了很多的答案,但每个人都有自己的解决方案,而我们有一个完整的(战斗)测试库的生态系统。

快速搜索NPMGitHub, X会给我们一些可爱的lib,我想浏览一些:

semver-compare是一个很棒的轻量级库(约230字节),如果你想按版本号排序,它特别有用,因为库的公开方法会适当地返回-101

库的核心:

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标志甚至通配符的版本(如次要/补丁版本:1.0.x1.0.*)

重点是:如果你可以通过你选择的包管理器找到合适的(unit-)测试版本,那么并不总是需要从Stack Overflow复制粘贴代码。

我的答案比这里的大多数答案都要简洁

/**
* Compare two semver versions. Returns true if version A is greater than
* version B
* @param {string} versionA
* @param {string} versionB
* @returns {boolean}
*/
export const semverGreaterThan = function(versionA, versionB){
var versionsA = versionA.split(/\./g),
versionsB = versionB.split(/\./g)
while (versionsA.length || versionsB.length) {
var a = Number(versionsA.shift()), b = Number(versionsB.shift())
if (a == b)
continue
return (a > b || isNaN(b))
}
return false
}

如果两个版本相等,函数将返回-1,如果第一个版本是最新版本,则返回0,而1表示第二个版本是最新版本。

let v1 = '12.0.1.0'
let v2 = '12.0.1'


let temp1 = v1.split('.');
let temp2 = v2.split('.');


console.log(compareVersion(temp1, temp2))




function compareVersion(version1, version2) {
let flag = false;
var compareResult;
let maxLength = Math.max(version1.length, version2.length);
let minLength = Math.min(version1.length, version2.length);


for (let i = 0; i < maxLength; ++i ) {
let result = version1[i] - version2[i];
if (result > 0) {
flag = true;
compareResult = 0;
break;
}
else if (result < 0) {
flag = true;
compareResult = 1;
break;
}


if (i === minLength) {
if (version1.length > version1.length) {
compareResult = version1[version1.length-1] > 0 ? '0' : '-1'
}  else  {
compareResult = version1[version2.length-1] > 0 ? '1' : '-1'
}
break;
}
}
if (flag === false) {
compareResult = -1;
}
return compareResult;
}

我不喜欢任何一个解决方案,所以我根据自己的编码偏好重新编写了它。请注意,最后四个检查结果与接受的答案略有不同。对我有用。

function v_check(version_a, version_b) {
// compares version_a as it relates to version_b
// a = b => "same"
// a > b => "larger"
// a < b => "smaller"
// NaN   => "invalid"


const arr_a = version_a.split('.');
const arr_b = version_b.split('.');


let result = "same"; // initialize to same // loop tries to disprove


// loop through a and check each number against the same position in b
for (let i = 0; i < arr_a.length; i++) {
let a = arr_a[i];
let b = arr_b[i];


// same up to this point so if a is not there, a is smaller
if (typeof a === 'undefined') {
result = "smaller";
break;


// same up to this point so if b is not there, a is larger
} else if (typeof b === 'undefined') {
result = "larger";
break;


// otherwise, compare the two numbers
} else {


// non-positive numbers are invalid
if (a >= 0 && b >= 0) {


if (a < b) {
result = "smaller";
break;
}
else if (a > b) {
result = "larger";
break;
}


} else {
result = "invalid";
break;
}
}
}


// account for the case where the loop ended but there was still a position in b to evaluate
if (result == "same" && arr_b.length > arr_a.length) result = "smaller";


return result;
}




console.log(v_check("1.7.1", "1.7.10"));  // smaller
console.log(v_check("1.6.1", "1.7.10"));  // smaller
console.log(v_check("1.6.20", "1.7.10")); // smaller
console.log(v_check("1.7.1", "1.7.10"));  // smaller
console.log(v_check("1.7", "1.7.0"));     // smaller
console.log(v_check("1.7", "1.8.0"));     // smaller


console.log(v_check("1.7.10", "1.7.1"));  // larger
console.log(v_check("1.7.10", "1.6.1"));  // larger
console.log(v_check("1.7.10", "1.6.20")); // larger
console.log(v_check("1.7.0", "1.7"));     // larger
console.log(v_check("1.8.0", "1.7"));     // larger


console.log(v_check("1.7.10", "1.7.10")); // same
console.log(v_check("1.7", "1.7"));       // same


console.log(v_check("1.7", "1..7")); // larger
console.log(v_check("1.7", "Bad"));  // invalid
console.log(v_check("1..7", "1.7")); // smaller
console.log(v_check("Bad", "1.7"));  // invalid

你可以使用String#localeCompareoptions

灵敏度

字符串中的哪些差异应该导致非零结果值。可能取值为:

  • "base":只有基本字母不同的字符串比较为不相等。例如:a ≠ ba = áa = A
  • "accent":只有在基本字母或重音和其他变音符标记上不同的字符串才会被比较为不相等。例如:a ≠ ba ≠ áa = A
  • "case":只有基本字母或大小写不同的字符串比较为不相等。例如:a ≠ ba = áa ≠ A
  • "variant":在基本字母、重音和其他变音符符号或大小写上不同的字符串比较为不相等。其他差异也可能被考虑在内。例如:a ≠ ba ≠ áa ≠ A

默认值是&;variant"用法"sort";它取决于使用“搜索”的区域。

数字

是否应该使用数字排序,这样"1"& lt;“2”;& lt;“10“。可能值为truefalse;默认值是false。这个选项可以通过options属性或Unicode扩展键来设置;如果两者都提供了,则options属性优先。实现不需要支持此属性。

var versions = ["2.0.1", "2.0", "1.0", "1.0.1", "2.0.0.1"];


versions.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));


console.log(versions);

我们现在可以使用Intl.Collator API来创建数字比较器。浏览器支持是相当不错的,但在撰写本文时Node.js中不支持。

const semverCompare = new Intl.Collator("en", { numeric: true }).compare;


const versions = ['1.0.1', '1.10.2', '1.1.1', '1.10.1', '1.5.10', '2.10.0', '2.0.1'];


console.log(versions.sort(semverCompare))


const example2 = ["1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"];
console.log(example2.sort(semverCompare))

我必须比较我的扩展版本,但我没有 在这里找到一个可行的解决方案。当比较1.89 >1.9 or 1.24.1 == 1.240.1

这里,我从零只在最后的记录1.1 == 1.10和1.10.1 >中下降的事实开始;1.1.1

compare_version = (new_version, old_version) => {
new_version = new_version.split('.');
old_version = old_version.split('.');
for(let i = 0, m = Math.max(new_version.length, old_version.length); i<m; i++){
//compare text
let new_part = (i<m-1?'':'.') + (new_version[i] || 0)
,   old_part = (i<m-1?'':'.') + (old_version[i] || 0);
//compare number (I don’t know what better)
//let new_part = +((i<m-1?0:'.') + new_version[i]) || 0
//,   old_part = +((i<m-1?0:'.') + old_version[i]) || 0;
//console.log(new_part, old_part);
if(old_part > new_part)return 0;    //change to -1 for sort the array
if(new_part > old_part)return 1
}
return 0
};
compare_version('1.0.240.1','1.0.240.1');   //0
compare_version('1.0.24.1','1.0.240.1');    //0
compare_version('1.0.240.89','1.0.240.9');  //0
compare_version('1.0.24.1','1.0.24');       //1

我不是一个大专家,但我构建了简单的代码来比较两个版本,将第一个返回值更改为-1以对版本数组进行排序

['1.0.240', '1.0.24', '1.0.240.9', '1.0.240.89'].sort(compare_version)
//results ["1.0.24", "1.0.240", "1.0.240.89", "1.0.240.9"]

和短版本的比较全字符串

c=e=>e.split('.').map((e,i,a)=>e[i<a.length-1?'padStart':'padEnd'](5)).join('');


//results "    1    0  2409    " > "    1    0  24089   "


c('1.0.240.9')>c('1.0.240.89')              //true

如果您有意见或改进,请不要犹豫提出建议。

我也遇到过类似的问题,而且我已经为它创建了一个解决方案。你可以试一试。

它为equal返回0,如果版本为greater则返回1,如果版本为less则返回-1

function compareVersion(currentVersion, minVersion) {
let current = currentVersion.replace(/\./g," .").split(' ').map(x=>parseFloat(x,10))
let min = minVersion.replace(/\./g," .").split(' ').map(x=>parseFloat(x,10))


for(let i = 0; i < Math.max(current.length, min.length); i++) {
if((current[i] || 0) < (min[i] || 0)) {
return -1
} else if ((current[i] || 0) > (min[i] || 0)) {
return 1
}
}
return 0
}




console.log(compareVersion("81.0.1212.121","80.4.1121.121"));
console.log(compareVersion("81.0.1212.121","80.4.9921.121"));
console.log(compareVersion("80.0.1212.121","80.4.9921.121"));
console.log(compareVersion("4.4.0","4.4.1"));
console.log(compareVersion("5.24","5.2"));
console.log(compareVersion("4.1","4.1.2"));
console.log(compareVersion("4.1.2","4.1"));
console.log(compareVersion("4.4.4.4","4.4.4.4.4"));
console.log(compareVersion("4.4.4.4.4.4","4.4.4.4.4"));
console.log(compareVersion("0","1"));
console.log(compareVersion("1","1"));
console.log(compareVersion("1","1.0.00000.0000"));
console.log(compareVersion("","1"));
console.log(compareVersion("10.0.1","10.1"));

我已经创建了这个解决方案,我希望你觉得它有用:

https://runkit.com/ecancino/5f3c6c59593d23001485992e


const quantify = max => (n, i) => n * (+max.slice(0, max.length - i))


const add = (a, b) => a + b


const calc = s => s.
split('.').
map(quantify('1000000')).
reduce(add, 0)


const sortVersions = unsortedVersions => unsortedVersions
.map(version => ({ version, order: calc(version) }))
.sort((a, b) => a.order - b.order)
.reverse()
.map(o => o.version)

2020年(大多数时候)正确的JavaScript答案

2020年3月的尼娜朔尔茨和2020年4月的Sid Vishnoi都给出了现代答案:

var versions = ["2.0.1", "2.0", "1.0", "1.0.1", "2.0.0.1"];


versions.sort((a, b) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
);


console.log(versions);

localCompare已经存在一段时间了

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator

但是1.01.0.1

localCompare没有解决这个问题,仍然返回1.0.1 , 1.0a

迈克尔·迪尔在他的(长&复杂)解决方案2013年就已经破解了

他将数字转换为另一个< em >基础,因此它们可以更好地排序

他的回答让我思考……

666 -不要用数字思考- 999

排序是字母数字,基于ASCII值,所以让我们(ab)使用ASCII作为“基础”;

我的解决方案是将1.0.2.1转换为b.a.c.bbacb,然后排序

这解决了1.1 vs. 1.0.0.0.1: bb vs. baaab

并立即用英国机场管理局巴布符号解决了1.01.0.1排序问题

转换是通过:

    const str = s => s.match(/(\d+)|[a-z]/g)
.map(c => c == ~~c ? String.fromCharCode(97 + c) : c);

=计算ASCII值0…999数字,否则连字母

1.0a祝辞祝辞祝辞[ "1" , "0" , "a" ]祝辞祝辞祝辞[ "b" , "a" , "a" ]

为了便于比较,没有必要用.join("")将它连接到一个字符串

Oneliner

const sortVersions=(x,v=s=>s.match(/(\d+)|[a-z]/g)
.map(c=>c==~~c?String.fromCharCode(97+c):c))
=>x.sort((a,b)=>v(b)<v(a)?1:-1)

测试代码片段:

function log(label,val){
document.body.append(label,String(val).replace(/,/g," - "),document.createElement("BR"));
}


let v = ["1.90.1", "1.9.1", "1.89", "1.090", "1.2", "1.0a", "1.0.1", "1.10", "1.0.0a"];
log('not sorted input :',v);


v.sort((a, b) => a.localeCompare(b,undefined,{numeric:true,sensitivity:'base'   }));
log(' locale Compare :', v); // 1.0a AFTER 1.0.1


const str = s => s.match(/(\d+)|[a-z]/g)
.map(c => c == ~~c ? String.fromCharCode(97 + c) : c);
const versionCompare = (a, b) => {
a = str(a);
b = str(b);
return b < a ? 1 : a == b ? 0 : -1;
}


v.sort(versionCompare);
log('versionCompare:', v);

注意1.090在两个结果中是如何排序的。

我的代码将解决一个答案中提到的001.012.001符号,但localeCompare得到了挑战的正确部分。

你可以结合这两种方法:

  • 当涉及字母时,使用.localCompareversionCompare进行排序

最终的JavaScript解决方案

const sortVersions = (
x,
v = s => s.match(/[a-z]|\d+/g).map(c => c==~~c ? String.fromCharCode(97 + c) : c)
) => x.sort((a, b) => (a + b).match(/[a-z]/)
? v(b) < v(a) ? 1 : -1
: a.localeCompare(b, 0, {numeric: true}))


let v=["1.90.1","1.090","1.0a","1.0.1","1.0.0a","1.0.0b","1.0.0.1"];
console.log(sortVersions(v));

最简单的方法是使用localeCompare:

a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })

这将返回:

  • 0:版本字符串是相等的
  • 1:版本号a大于b
  • -1:版本号b大于a

以下是我的解决方案,适用于任何深度的任何版本。

自动处理数字+点问题。如果不是这样,函数存在,控制台日志将给出undefined而不是true, false或true。

自动处理尾随零问题。

任何可能的地方都存在自动继电器。

自动向后兼容旧浏览器。

function checkVersion (vv,vvv){
if(!(/^[0-9.]*$/.test(vv) && /^[0-9.]*$/.test(vvv))) return;
va = vv.toString().split('.');
vb = vvv.toString().split('.');
length = Math.max(va.length, vb.length);
for (i = 0; i < length; i++) {


if ((va[i]|| 0) < (vb[i]|| 0)  ) {return false; }
}
return true;}
  

console.log(checkVersion('20.0.0.1' , '20.0.0.2'));
console.log(checkVersion(20.0 , '20.0.0.2'));
console.log(checkVersion('20.0.0.0.0' , 20));
console.log(checkVersion('20.0.0.0.1' , 20));
console.log(checkVersion('20.0.0-0.1' , 20));

一个非常简单的方法:

function compareVer(previousVersion, currentVersion) {
try {
const [prevMajor, prevMinor = 0, prevPatch = 0] = previousVersion.split('.').map(Number);
const [curMajor, curMinor = 0, curPatch = 0] = currentVersion.split('.').map(Number);


if (curMajor > prevMajor) {
return 'major update';
}
if (curMajor < prevMajor) {
return 'major downgrade';
}
if (curMinor > prevMinor) {
return 'minor update';
}
if (curMinor < prevMinor) {
return 'minor downgrade';
}
if (curPatch > prevPatch) {
return 'patch update';
}
if (curPatch < prevPatch) {
return 'patch downgrade';
}
return 'same version';
} catch (e) {
return 'invalid format';
}
}

输出:

compareVer("3.1", "3.1.1") // patch update
compareVer("3.1.1", "3.2") // minor update
compareVer("2.1.1", "1.1.1") // major downgrade
compareVer("1.1.1", "1.1.1") // same version

我想为我为解决这个问题而做的轻量级库做广告:semantic-version

可以同时使用面向对象(OO)和面向函数。它可以作为npm-package和现成的包文件使用。

const compareAppVersions = (firstVersion, secondVersion) => {
const firstVersionArray = firstVersion.split(".").map(Number);
const secondVersionArray = secondVersion.split(".").map(Number);
const loopLength = Math.max(
firstVersionArray.length,
secondVersionArray.length
);
for (let i = 0; i < loopLength; ++i) {
const a = firstVersionArray[i] || 0;
const b = secondVersionArray[i] || 0;
if (a !== b) {
return a > b ? 1 : -1;
}
}
return 0;
};

如果不允许使用字母或符号,那么代码行数就很少。如果您控制了版本控制方案,并且不是第三方提供的,那么这种方法是有效的。

// we presume all versions are of this format "1.4" or "1.10.2.3", without letters
// returns: 1 (bigger), 0 (same), -1 (smaller)
function versionCompare (v1, v2) {
const v1Parts = v1.split('.')
const v2Parts = v2.split('.')
const length = Math.max(v1Parts.length, v2Parts.length)
for (let i = 0; i < length; i++) {
const value = (parseInt(v1Parts[i]) || 0) - (parseInt(v2Parts[i]) || 0)
if (value < 0) return -1
if (value > 0) return 1
}
return 0
}


console.log(versionCompare('1.2.0', '1.2.4') === -1)
console.log(versionCompare('1.2', '1.2.0') === 0)
console.log(versionCompare('1.2', '1') === 1)
console.log(versionCompare('1.2.10', '1.2.1') === 1)
console.log(versionCompare('1.2.134230', '1.2.2') === 1)
console.log(versionCompare('1.2.134230', '1.3.0.1.2.3.1') === -1)

function compare(versionA: string | undefined, versionB: string | undefined, operator: string = '>') {
if (versionA === undefined || versionB === undefined) {
return false
}
const listA = versionA.split('.')
const listB = versionB.split('.')
let a = []
let b = []
for (let i = 0; i < listA.length; i++) {
a.push(parseInt(listA[i].replace(/\D/g, ''), 10))
b.push(parseInt(listB[i].replace(/\D/g, ''), 10))
}


for (let i = 0; i < listA.length; i++) {
switch (operator) {
case '>':
case '>=':
if (a[i] === b[i]) {
continue
}
if (a[i] > b[i]) {
return true
}
if (a[i] < b[i]) {
return false
}
break
case '<':
case '<=':
if (a[i] === b[i]) {
continue
}
if (a[i] > b[i]) {
return false
}
if (a[i] < b[i]) {
return true
}
break
case '=':
if (a[i] > b[i]) {
return false
}
if (a[i] < b[i]) {
return false
}
break
}
}
switch (operator) {
case '>':
return false
case '<':
return false
case '=':
case '>=':
case '<=':
return true
}
}

你可以使用JavaScript的localeCompare方法:

a.localeCompare(b, undefined, { numeric: true })

这里有一个例子:

"1.1".localeCompare("2.1.1", undefined, { numeric: true }) =比;-1

"1.0.0".localeCompare("1.0", undefined, { numeric: true }) =比;1

"1.0.0".localeCompare("1.0.0", undefined, { numeric: true }) =比;0

基于伊丹的精彩回答,下面的函数semverCompare传递了语义版本控制 2.0.0的大多数情况。看到这是更多要点

function semverCompare(a, b) {
if (a.startsWith(b + "-")) return -1
if (b.startsWith(a + "-")) return  1
return a.localeCompare(b, undefined, { numeric: true, sensitivity: "case", caseFirst: "upper" })
}

它返回:

  • -1: a <b
  • 0: a == b
  • 1: a >b
将其转换为一个数字,然后比较。 假设每个主要/次要/补丁使用不超过3个数字,并且没有标签 (像这个1.12.042)

const versionNumber = +versionString
.split('.')
.map(v => '000' + v)
.map(v => v.slice(-3))
.join('');

两个版本比较

const val = '1.2.3 5.4.3';
const arr = val.split(' ');
let obj = {};
for(let i = 0; i<2; i++) {
const splitArr = arr[i].split('.')
const reduced = splitArr.reduce((pre,
curr)=>parseInt(pre)+parseInt(curr));
obj[i] = reduced;
}
if(obj[0]>obj[1]) {
console.log(arr[0]);
} else {
console.log(arr[1]);
}