以下是软件版本号:

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

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


当前回答

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

其他回答

最简单的方法是使用localeCompare:

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

这将返回:

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

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

这个排序函数是针对语义版本的,它处理的是解析版本,所以它不能处理像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;
}

下面是一个适合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

你可以使用带有选项的String#localeCompare

sensitivity Which differences in the strings should lead to non-zero result values. Possible values are: "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A. "accent": Only strings that differ in base letters or accents and other diacritic marks compare as unequal. Examples: a ≠ b, a ≠ á, a = A. "case": Only strings that differ in base letters or case compare as unequal. Examples: a ≠ b, a = á, a ≠ A. "variant": Strings that differ in base letters, accents and other diacritic marks, or case compare as unequal. Other differences may also be taken into consideration. Examples: a ≠ b, a ≠ á, a ≠ A. The default is "variant" for usage "sort"; it's locale dependent for usage "search". numeric Whether numeric collation should be used, such that "1" < "2" < "10". Possible values are true and false; the default is false. This option can be set through an options property or through a Unicode extension key; if both are provided, the options property takes precedence. Implementations are not required to support this property.

var版本=[" 2.0.1”、“2.0”、“1.0”、“1.0.1”,“2.0.0.1”); 版本。sort((a, b) => a.localeCompare(b, undefined, {numeric: true,灵敏度:'base'})); console.log(版本);

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

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