如何使用js比较软件版本号?(唯一号码)

Tat*_*tat 145 javascript sorting

这是软件版本号:

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"
Run Code Online (Sandbox Code Playgroud)

我该如何比较?假设正确的顺序是:

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"
Run Code Online (Sandbox Code Playgroud)

这个想法很简单......:读取第一个数字,然后读取第二个数字,然后读取第三个数字....但是我无法将版本号转换为浮点数....你也可以看到版本号就像这个:

"1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1.0"
Run Code Online (Sandbox Code Playgroud)

这更清楚地看到背后的想法是什么......但是,如何将其转换为计算机程序?有没有人知道如何排序这个?谢谢.

Jon*_*Jon 122

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

需要记住的一些重要细节:

  1. 如何比较每对中的部件?这个问题想要在数字上进行比较,但是如果我们的版本字符串不仅仅是数字(例如"1.0a")呢?
  2. 如果一个版本字符串的部分多于另一个版本,会发生什么?最有可能"1.0"应该被认为小于"1.0.1",但是"1.0.0"呢?

这是您可以直接使用的实现的代码(gist with documentation):

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;
}
Run Code Online (Sandbox Code Playgroud)

该版本自然地比较部分,不接受字符后缀并认为"1.7"小于"1.7.0".比较模式可以更改为词典编纂,较短版本的字符串可以使用可选的第三个参数自动进行零填充.

有一个JSFiddle 在这里运行"单元测试" ; 它是ripper234工作的略微扩展版本(谢谢).

重要说明:此代码使用Array.mapArray.every,这意味着它不会在早于9的IE版本中运行.如果需要支持那些,则必须为缺少的方法提供polyfill.

  • 这是一个带有一些单元测试的改进版本:http://jsfiddle.net/ripper234/Xv9WL/28/ (15认同)
  • 嘿All,我把这个要点变成了一个带有测试和一切的gitrepo并把它放在npm和bower上,这样我就可以更容易地将它包含在我的项目中.https://github.com/gabe0x02/version_compare (5认同)
  • 例如,如果我们将“11.1.2”与“3.1.2”进行比较,您的算法就无法正常工作。在比较它们之前,您应该将字符串转换为整数。请解决这个问题;) (3认同)
  • @GabrielLittman:已经[由经验丰富的开发人员编写的已建立的库](https://github.com/gabe0x02/version_compare/issues/1)执行semver比较. (3认同)
  • @GabrielLittman:嘿,谢谢花时间去做!但是,SO上的所有代码都默认使用[CC-BY-SA](http://creativecommons.org/licenses/by-sa/2.5/).这意味着你不能让你的包得到GPL许可.我知道律师不是任何人在这里的,但如果你修理它会很好. (2认同)
  • @GabrielLittman:GPL实际上是非常严格的,因为你被迫GPL许可所有与现有GPL代码接触的代码.无论如何,为了将来的参考:一个好的和广泛使用的"做任何你想要的,没有附加条件"许可证是[麻省理工学院](http://en.wikipedia.org/wiki/MIT_License). (2认同)
  • @ripper234 它不能正常工作:`assert(compareVersionNumbers("1.7.9", "1.7.10") &lt; 0);` (2认同)

小智 67

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, '*')
Run Code Online (Sandbox Code Playgroud)

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

  • 是.**这个**是正确的答案 - 比较版本是非常重要的(参见http://semver.org上的#11),并且有生产级库可以完成这项工作. (6认同)
  • 从技术上讲,它不是正确的答案,因为node.js和javascript是不同的.我认为最初的问题更多针对浏览器.但谷歌把我带到了这里,幸运的是我正在使用节点:) (6认同)
  • semver 仅支持 ABC 样式版本。如果您需要使用 ABCD 版本(如问题中所建议的),那么您就不走运了。 (4认同)
  • semver 它是一个 npm 包,它可以在任何 JS 环境中使用!这是正确答案 (3认同)
  • NodeJS 不仅是服务器端唯一的解决方案。Electron 框架为桌面应用程序嵌入了一个 nodeJS。这实际上是我一直在寻找的答案。 (2认同)
  • @artuska好吧,然后简单地去买另一个像[semver-compare](https://github.com/substack/semver-compare)的软件包-233B(小于0.5kB!)gzip压缩了:) (2认同)

Joe*_*Joe 48

// 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"));
Run Code Online (Sandbox Code Playgroud)


LeJ*_*red 42

这个非常小但速度非常快的比较函数可以获取任何长度的版本号每个段的任何数字大小.

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

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

编辑: Bugfixed版本剥离尾随零以识别"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"]
Run Code Online (Sandbox Code Playgroud)

  • @emragins :我看不出它在哪里失败。它输出```["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"] ``` 你的代码输出 ```["0.0", "0.0.0", " 0.4.1", "0.5", "1", "1.0.0", "1.1", "1.2.15", "1.25.4", "2", "2.5.0", "2.5.10" , "2.5.10.4159", "10.5"] ```,完全相同,因为 0.0 和 0.0.0 被认为是*相等的*,这意味着 '0.0' 是否在 '0.0.0 之前是无关紧要的' 或相反亦然。 (2认同)

Ida*_*dan 15

最简单的是使用localeCompare

a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })  
Run Code Online (Sandbox Code Playgroud)

这将返回:

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

  • 这非常有效。❤︎ 谢谢。 (3认同)
  • 这是最简单的答案,爱它! (3认同)
  • 喜欢它,但不幸的是它可以通过这个测试“1.0.0-alpha &lt; 1.0.0”。请参阅 https://semver.org/#spec-item-11 (3认同)
  • 支持 `1.0.0-alpha &lt; 1.0.0` 和更多情况的补丁:https://gist.github.com/iwill/a83038623ba4fef6abb9efca87ae9ccb (2认同)

use*_*621 14

取自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;
    }
Run Code Online (Sandbox Code Playgroud)


Vik*_*tor 9

无法在这里找到我想做的功能.所以我写了自己的.这是我的贡献.我希望有人觉得它很有用.

优点:

  • 处理任意长度的版本字符串.'1'或'1.1.1.1.1'.

  • 如果未指定,则将每个值默认为0.仅仅因为字符串更长并不意味着它是一个更大的版本.('1'应与'1.0'和'1.0.0.0'相同.)

  • 比较数字而非字符串.('3'<'21'应该是真的.不是假的.)

  • 不要在循环中浪费时间在无用的比较上.(比较==)

  • 您可以选择自己的比较器.

缺点:

  • 它不处理版本字符串中的字母.(我不知道那会怎么样?)

我的代码,类似于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);
}
Run Code Online (Sandbox Code Playgroud)

示例:

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
Run Code Online (Sandbox Code Playgroud)

  • 如果比较器参数与未经检查的用户输入一起使用,则此函数容易发生代码注入!示例: compareVersions('1.2', '==0;alert("cotcha");', '1.2'); (2认同)

Nin*_*olz 9

你可以String#localeCompare使用options

\n
\n

灵敏度

\n

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

\n
    \n
  • "base":只有基本字母不同的字符串才比较为不相等。例子:a \xe2\x89\xa0 ba = \xc3\xa1a = A
  • \n
  • "accent":只有基本字母或重音符号以及其他变音符号不同的字符串才会被视为不相等。例子:a \xe2\x89\xa0 ba \xe2\x89\xa0 \xc3\xa1a = A
  • \n
  • "case":只有基本字母或大小写不同的字符串才比较为不相等。例子:a \xe2\x89\xa0 ba = \xc3\xa1a \xe2\x89\xa0 A
  • \n
  • "variant":基本字母、重音符号和其他变音符号不同或大小写不同的字符串比较为不相等。还可以考虑其他差异。例子:a \xe2\x89\xa0 ba \xe2\x89\xa0 \xc3\xa1a \xe2\x89\xa0 A
  • \n
\n

默认为“variant”,用于“sort”用法;它的使用“搜索”取决于区域设置。

\n

数字

\n

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

\n
\n

\r\n
\r\n
var versions = ["2.0.1", "2.0", "1.0", "1.0.1", "2.0.0.1"];\n\nversions.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: \'base\' }));\n\nconsole.log(versions);
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n


van*_*owm 7

这是另一个短版本,适用于任意数量的子版本、填充零甚至带字母的数字 (1.0.0b3)

function compareVer(a, b)
{
    function prep(t)
    {
        return ("" + t)
          //treat non-numerical characters as lower version
          //replacing them with a negative number based on charcode of first character
          .replace(/[^0-9\.]+/g, function(c){return "." + ((c = c.replace(/[\W_]+/, "")) ? c.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('.');
    }
    a = prep(a);
    b = prep(b);
    for (var i = 0; i < Math.max(a.length, b.length); i++)
    {
        //convert to integer the most efficient way
        a[i] = ~~a[i];
        b[i] = ~~b[i];
        if (a[i] > b[i])
            return 1;
        else if (a[i] < b[i])
            return -1;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

函数返回:

0a = b

1a > b

-1a < b

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
Run Code Online (Sandbox Code Playgroud)

/*use strict*/

function compareVer(a, b)
{
  a = compareVer.prep(a);
  b = compareVer.prep(b);
  for (var i = 0; i < Math.max(a.length, b.length); i++)
  {
    //convert to integer the most efficient way
    a[i] = ~~a[i];
    b[i] = ~~b[i];
    if (a[i] > b[i])
      return 1;
    else if (a[i] < b[i])
      return -1;
  }
  return 0;
}
compareVer.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 = c.replace(/[\W_]+/, "")) ? c.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('.');


//examples

var type = {
  "-1": " < ",
   "0": " = ",
   "1": " > "
}
var 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(var i = 0, t; i < list.length; i++)
{
  t = list[i][0] + type[compareVer(list[i][0], list[i][1])] + list[i][1]
  document.body.innerHTML += t + "<br>";
  console.log(t);
}
Run Code Online (Sandbox Code Playgroud)

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


per*_*mon 6

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;
    }
Run Code Online (Sandbox Code Playgroud)

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

 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;
 }
Run Code Online (Sandbox Code Playgroud)

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

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

在这里,我用零填充每个部分到 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
Run Code Online (Sandbox Code Playgroud)


小智 6

我遇到了类似的问题,并且我已经为其创建了解决方案。请随意尝试一下。

它返回0for equal1如果版本是greater并且-1如果是less

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"));
Run Code Online (Sandbox Code Playgroud)


pow*_*tac 5

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

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

version_compare('2.0', '2.0.0.1', '<'); 
// returns true
Run Code Online (Sandbox Code Playgroud)


小智 5

如果这个想法已经在我没有看到的链接中被访问过,请原谅我。

我在将部分转换为加权总和方面取得了一些成功,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

这使得比较非常容易(比较双精度)。我们的版本字段永远不会超过 4 位数字。

7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0
Run Code Online (Sandbox Code Playgroud)

我希望这对某人有所帮助,因为多个条件似乎有点矫枉过正。

  • 如果 this.minor &gt; 999(将与主要重叠),这将中断 (2认同)

Art*_*újo 5

Simple and short function:

function isNewerVersion (oldVer, newVer) {
  const oldParts = oldVer.split('.')
  const newParts = newVer.split('.')
  for (var i = 0; i < newParts.length; i++) {
    const a = parseInt(newParts[i]) || 0
    const b = parseInt(oldParts[i]) || 0
    if (a > b) return true
    if (a < b) return false
  }
  return false
}
Run Code Online (Sandbox Code Playgroud)

Tests:

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
Run Code Online (Sandbox Code Playgroud)

  • 您可以将其简化为: **const a = ~~newParts[i];** 事实上,这是将字符串转换为整数的最有效方法,如果变量未定义或包含非数字字符,则返回 0。 (2认同)

kan*_*ano 5

尽管这个问题已经有很多答案,但每个人都在推广自己的后院酿造解决方案,而我们为此拥有一个完整的(经过战斗)测试的库生态系统。

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

semver-compare是一个很棒的轻量级 (~230B) 库,如果您想按版本号排序,因为库的公开方法返回-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;
};
Run Code Online (Sandbox Code Playgroud)

compare-semver 大小相当大(约 4.4kB gzipped),但允许一些很好的独特比较,比如找到一堆版本的最小值/最大值,或者找出所提供的版本是唯一的还是比集合中的任何其他版本都少版本。

compare-versions是另一个小库(~630B gzipped)并很好地遵循规范,这意味着您可以将版本与 alpha/beta 标志甚至通配符进行比较(例如次要/补丁版本:1.0.x1.0.*

重点是:如果您可以通过您选择的包管理器找到合适的(单元)测试版本,则并不总是需要从 StackOverflow 复制粘贴代码。


Sud*_*noi 5

我们现在可以使用Intl.CollatorAPI 来创建数字比较器。浏览器支持相当不错,但在撰写本文时 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))
Run Code Online (Sandbox Code Playgroud)


Dan*_*man 5

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

Nina Scholz在 2020 年 3 月和 Sid Vishnoi在 2020 年 4 月都发布了现代答案:

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);
Run Code Online (Sandbox Code Playgroud)

localCompare 已经存在了一段时间了

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

但是1.0a1.0.1呢?

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

Michael Deal 在他的(又长又复杂)的解决方案中已经在 2013 年破解了这个问题

他将Numbers转换为另一个Base,以便更好地排序

他的回答让我思考...

666 - 不要用数字思考 - 999

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

我的解决方案是将1.0.2.1转换为 bacbbacb,然后排序

这可以通过以下方式解决1.11.0.0.0.1 的问题:bbbaaab

并立即解决了1.0a1.0.1 的排序问题,符号为:baabab

转换是通过以下方式完成的:

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

= 计算 0...999 数字的 ASCII 值,否则连接字母

1.0a>>> [ "1" , "0" , "a" ]>>>[ "b" , "a" , "a" ]

为了进行比较,无需将其连接到一个字符串.join("")

内线

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)
Run Code Online (Sandbox Code Playgroud)

测试片段:

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);
Run Code Online (Sandbox Code Playgroud)

请注意1.090在两个结果中的排序方式。

我的代码无法解决一个答案中提到的001.012.001符号,但它localeCompare正确地解决了这部分挑战。

您可以结合使用这两种方法:

  • 当涉及字母时用.localCompareOR排序versionCompare

最终的 JavaScript 解决方案

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


Jer*_*yal 5

一个非常简单的方法:

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';
  }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)