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

时间:2011-07-26 15:31:49

标签: javascript sorting

以下是软件版本号:

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

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

49 个答案:

答案 0 :(得分:114)

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

要记住一些重要细节:

  1. 如何比较每对中的部件?问题想要在数字上进行比较,但是如果我们的版本字符串不仅仅由数字组成(例如“1.0a”)会怎样?
  2. 如果一个版本字符串的部分比另一个更多,会发生什么?最有可能“1.0”应该被认为小于“1.0.1”,但是“1.0.0”呢?
  3. 以下是您可以直接使用的实现代码(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;
    }
    

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

    有一个JSFiddle运行“单元测试”here;它是ripper234's work的略微扩展版本(谢谢)。

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

答案 1 :(得分:54)

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

答案 2 :(得分:47)

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

答案 3 :(得分:42)

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

返回值:
- 如果a&lt; < 0 b
- 如果a>&gt;则为> 0。 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"]

答案 4 :(得分: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;
    }

答案 5 :(得分:10)

最简单的是使用 localeCompare :

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

这将返回:

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

答案 6 :(得分:8)

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

<强>优点:

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

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

  • 比较数字而不是字符串。 ('3'&lt; '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);
}

<强>实施例

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

答案 7 :(得分:4)

请原谅我这个想法是否已经在我未见过的链接中访问过。

我将部件转换为加权总和方面取得了一些成功:

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

这使比较变得非常容易(比较双倍)。 我们的版本字段不超过4位。

7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0

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

答案 8 :(得分:4)

死的简单方法:

function compare(previousVersion, currentVersion){

    //returns int array [1,1,1] i.e. [major,minor,patch]
    var previousVerArr = previousVersion.split('.').map(Number); 
    var currentVerArr = currentVersion.split('.').map(Number);
  
    if (currentVerArr[0] > previousVerArr[0]) {
      console.log("major");
    } else if (currentVerArr[0] == previousVerArr[0] && currentVerArr[1] > previousVerArr[1]) {
      console.log("minor");
    } else if (currentVerArr[0] == previousVerArr[0] && currentVerArr[1] == previousVerArr[1] && currentVerArr[2] > previousVerArr[2]) {
      console.log("patch");
    } else {
      console.log("same or downgrade version");
    }
  }

输出:

compare(1.1.1, 2.1.1) // major
compare(1.1.1, 1.2.1) // minor
compare(1.1.1, 1.1.2) // patch
compare(1.1.1, 0.1.1) // same or downgrade version

答案 9 :(得分:4)

检查功能version_compare() from the php.js project。它类似于PHP's version_compare()

您可以像这样使用它:

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

答案 10 :(得分:3)

这是另一个简短版本,可与任意数量的子版本一起使用,填充零甚至带有字母(1.0.0b3)的数字

function compareVer(a, b)
{
    //treat non-numerical characters as lower version
    //replacing them with a negative number based on charcode of each character
    function fix(s)
    {
        return "." + (s.toLowerCase().charCodeAt(0) - 2147483647) + ".";
    }
    a = ("" + a).replace(/[^0-9\.]/g, fix).split('.');
    b = ("" + b).replace(/[^0-9\.]/g, fix).split('.');
    var c = Math.max(a.length, b.length);
    for (var i = 0; i < c; 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;
}

输出:

0 :a = b

1 :a> b

-1 :a

/*use strict*/

function compareVer(a, b)
{
    //treat non-numerical characters as lover version
    //replacing them with a negative number based on charcode of each character
    function fix(s)
    {
        return "." + (s.toLowerCase().charCodeAt(0) - 2147483647) + ".";
    }
    a = ("" + a).replace(/[^0-9\.]/g, fix).split('.');
    b = ("" + b).replace(/[^0-9\.]/g, fix).split('.');
    var c = Math.max(a.length, b.length);
    for (var i = 0; i < c; 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;
}

var type = {
  "-1": " < ",
   "0": " = ",
   "1": " > "
};
var list = [
  ["1.0.0.0.0.0", "1.0"],
  ["1.0",         "1.0.1"],
  ["1.0b1",       "1.0"],
  ["1.0a",        "1.0b"],
  ["1.1",         "1.0.1b"],
  ["1.1alpha",    "1.1beta"],
  ["1.1rc1",      "1.1beta"],
  ["1.0001",      "1.00000.1.0.0.0.01"]
];

for(var i = 0; i < list.length; i++)
{
  console.log(list[i][0] + type[compareVer(list[i][0], list[i][1])] + list[i][1]);
}

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

答案 11 :(得分:3)

2017回答:

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

compareVersion(v1,v2) // return true

function compareVersion(ver1, ver2) {
        ver1 = ver1.split('.')
        ver2 = ver2.split('.')
        var i = 0, v1, v2;
        ver1 = Array.isArray(ver1) ? ver1 : [ver1];
        /*default is true*/
        while (i < 4) {
            v1 = ver1[i]; v2 = ver2[i];
            if (!v1 || !v2) return true;
            if (v1 * 1 < v2 * 1) return false;
            i++;
        }
        return true;
    }

对于不支持IE(padStart之湖)的浏览器,更酷的答案是:

 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" // return false, but it wrong "123" "> "099" // but padding the short number with zeros make the comparision to be right

所以解决方案的想法是用零填充版本的所有部分,所以所有数字都在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

答案 12 :(得分:3)

您可以将String#localeComparesums一起使用

敏感性

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

  • options:仅将基本字母不同的字符串视为不相等。示例:"base"a ≠ ba = á
  • a = A:仅将基本字母或重音和其他音标不同的字符串视为不相等。示例:"accent"a ≠ ba ≠ á
  • a = A:仅将基本字母或大小写不同的字符串视为不相等。示例:"case"a ≠ ba = á
  • a ≠ A:基本字母,重音和其他变音符号或大小写不同的字符串比较不相等。还可以考虑其他差异。示例:"variant"a ≠ ba ≠ á

对于用法“ sort”,默认值为“ variant”;它取决于使用“搜索”的语言环境。

数字

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

options

答案 13 :(得分:3)

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

它为0返回equal,如果版本为1,则返回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"));

答案 14 :(得分:2)

我们现在可以使用Intl.Collator API来创建数字比较器。 Browser support相当不错,但在撰写本文时,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))

答案 15 :(得分:2)

简单和简短的功能:

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
}

测试:

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

答案 16 :(得分:2)

// 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
    }

答案 17 :(得分:2)

以下是适用于Array.sort的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

答案 18 :(得分:1)

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

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

或者这里是递归版

void camera(int x, int y)
{
    GLfloat xoff = x- lastX;
    GLfloat yoff = lastY - y; // Reversed since y-coordinates range from bottom to top
    lastX = x;
    lastY = y;

    GLfloat sensitivity = 0.5f;
    xoff *= sensitivity;
    yoff *= sensitivity;

    yaw += xoff;                // yaw is x
    pitch += yoff;              // pitch is y

    // Limit up and down camera movement to 90 degrees
    if (pitch > 89.0)
        pitch = 89.0;
    if (pitch < -89.0)
        pitch = -89.0;

    // Update camera position and viewing angle
    Front.x = cos(convertToRads(yaw) * cos(convertToRads(pitch)));
    Front.y = sin(convertToRads(pitch));
    Front.z = sin(convertToRads(yaw)) * cos(convertToRads(pitch));
}

答案 19 :(得分:1)

例如,如果我们要检查当前jQuery版本是否小于1.8,那么parseFloat($.ui.version) < 1.8 )会在版本为“1.10.1”时给出错误的结果,因为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/

答案 20 :(得分:1)

查看此blog post。此功能适用于数字版本号。

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

答案 21 :(得分:1)

replace()函数仅替换字符串中的第一个出现。因此,我们将.替换为,。然后删除所有.并再次将,设为.并将其解析为浮动。

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

最后,排序:

versions.sort();

答案 22 :(得分: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"]

答案 23 :(得分:1)

这个想法是比较两个版本,知道哪个是最大的。我们删除&#34;。&#34;我们将矢量的每个位置与另一个位置进行比较。

// 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;
      }
   }
}

答案 24 :(得分:1)

我的答案不如这里的大多数答案

/**
 * 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
}

答案 25 :(得分:1)

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

功能

  • 无序列限制'1.0.1.5.53.54654.114.1.154.45'作品
  • 序列长度无限制:'1.1546515465451654654654654138754431574364321353734'作品
  • 可以按版本排序对象(参见自述文件)
  • 阶段(如alpha,beta,rc1,rc2)

如果您需要其他功能,请随时打开问题。

答案 26 :(得分:1)

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

2020年3月的Nina Scholz和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.0a 1.0.1

localCompare不能解决问题,仍然返回1.0.1 , 1.0a

Michael Deal处理他的(冗长而复杂的)解决方案already cracked that in 2013

他将 Numbers 转换为另一个 Base ,因此可以更好地对其进行排序

他的回答让我开始思考...

666-不要以数字思考-999

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

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

使用 bb vs. baaab 1.1 vs. 1.0.0.0.1 >

并立即解决 1.0a 1.0.1 排序问题,其符号为: baa bab < / p>

转换通过以下方式完成:

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

=计算0 ... 999个数字的ASCII值,否则为concat字母

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

答案 27 :(得分:0)

如果版本相等,该函数将返回-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;
}

答案 28 :(得分:0)

我不喜欢任何一种解决方案,因此我根据自己的编码偏好将其重写。请注意,最后四项检查的结果与接受的答案略有不同。为我工作。

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

答案 29 :(得分:0)

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

NPMGitHub,X上进行快速搜索将为我们提供一些可爱的库,而我想遍历以下内容:

semver-compare是一个很棒的轻量级(〜230B)库,如果要按版本号排序,该库特别有用,因为库的暴露方法返回payload: {name: "aaa", number: "111"}-1或{{1 }}。

库的核心:

0

compare-semver的大小相当大(压缩后约为4.4kB),但允许进行一些不错的独特比较,例如查找一叠版本的最小值/最大值或查找所提供的版本是否唯一或少于版本集合中的任何其他内容。

compare-versions是另一个小库(大约压缩了630B),符合规范,这意味着您可以比较带有alpha / beta标志甚至通配符的版本(例如次要/补丁版本:1module.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; };

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

答案 30 :(得分:0)

这是我的解决方案适用于任一版本的任何深度级别。

自动处理数字+点问题。如果不是这样,那么函数存在并且控制台日志将给出 undefined 而不是真实的 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));

答案 31 :(得分:0)

我也可以为我为解决这个问题而制作的轻量级库做广告吗?

https://github.com/pearnaly/semantic-version

您可以同时使用它面向对象和面向函数。它以 npm-package 和即用型捆绑文件的形式提供。

答案 32 :(得分:0)

我不得不比较我的扩展程序的版本,但是在这里找不到可行的解决方案,在比较1.89> 1.9或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

我不是专家,但是我构建了简单的代码来比较2个版本,将第一个返回值更改为-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

如果您有任何意见或改进,请随时提出建议

答案 33 :(得分:0)

我已经创建了此解决方案,希望您觉得它有用:

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)

答案 34 :(得分:0)

这是我的解决方案。它已在leetcode上接受。我今天在采访中遇到了这个问题。但是我当时没有解决。 我又想了一遍。加零使两个数组的长度相等。然后比较。

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

答案 35 :(得分:0)

这是一个订购版本字符串而不分配任何子字符串或数组的版本。由于它分配的对象较少,因此GC的工作量较少。

有一对分配(允许重用if(array_key_exists('userid',$_REQUEST)) { echo $_REQUEST['userid']; } else { echo 'no userid.'; } 方法),但如果您对性能非常敏感,可以将其扩展为完全避免分配。

getVersionPart

答案 36 :(得分:0)

这是另一种使用递归算法的方法。

此代码只使用Array.shift和递归,这意味着它可以在IE 6+中运行。如果您有任何疑问,可以访问my 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

答案 37 :(得分:0)

我认为值得分享的另一个实现,因为它简短而强大。请注意,它仅使用数字比较。通常它会检查版本2是否晚于版本1,如果是这种情况则返回true。假设你有version1:1.1.1和version2:1.1.2。它通过两个版本的每个部分添加它们的部分如下:(1 + 0.1)然后(1.1 + 0.01)版本1和(1 + 0.1)然后(1.1 + 0.02)版本2.

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

答案 38 :(得分:0)

在排序之前预处理版本意味着不会多次调用parseInt。 使用类似于Michael Deal建议的Array#map,这是我用来查找标准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"

答案 39 :(得分:0)

你不能把它们转换成数字然后按大小排序吗?将0添加到&lt;的数字的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  )
});

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

答案 40 :(得分: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”,由Semantic versionning 2.0.0指定

答案 41 :(得分:0)

对于提出的问题,这不是一个很好的解决方案,但它非常相似。

此排序功能适用于semantic versions,它处理已解决的版本,因此它不适用于x*等通配符。

它适用于此正则表达式匹配的版本:/\d+\.\d+\.\d+.*$/。它与this answer非常相似,只是它适用于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;
}

答案 42 :(得分:0)

我是根据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,这对于正常比较来说已经足够了。这里解释错误:How to deal with floating point number precision in 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

答案 43 :(得分:0)

我喜欢来自the version@mar10,但从我的观点来看,有可能出现误用(如果版本与Semantic Versioning文档兼容,似乎不是这种情况,但如果使用某些“内部版本号”,可能就是这种情况:

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

然后是完整版(是@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;
}

P.S。它更慢,但也可以考虑重新使用相同的比较函数来操作字符串实际上是字符数组的事实:

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

答案 44 :(得分:0)

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

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

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

答案 45 :(得分:-1)

您可以遍历每个以句点分隔的字符并将其转换为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?
}

答案 46 :(得分:-1)

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;
            },

答案 47 :(得分:-1)

这是一种有趣的方式OO:

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

答案 48 :(得分:-1)

这实际上取决于versioning system背后的逻辑。每个数字代表什么,以及如何使用它。

每个颠覆都是指定开发阶段的数字吗? 0代表alpha 1为测试版 2候选人 3(最终)发布

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

一旦您了解版本控制系统的工作原理,就可以轻松创建算法。

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

如果在任何颠覆中允许大于9的数字,有几种方法可以比较它们。最明显的是将字符串除以小数并比较每列。

但是在不知道版本控制系统是如何工作的情况下,在发布版本1.0.2a时,实现上述过程会变得很难。