以下是软件版本号:

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

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


当前回答

我根据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个数字在任何部分,你可以改变除法数学。Pow (10, I * 3);;

输出如下所示:

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

其他回答

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

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

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

当我在控制台中运行下面的代码时,它是有意义的,并且使用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"]

这是一个巧妙的技巧。如果您正在处理数值,在特定的值范围内,您可以为版本对象的每个级别分配一个值。例如,“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);

你可以使用带有选项的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(版本);

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

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)在他的(略长且复杂的)解决方案中已经在2013年解决了这个问题

他将数字转换为另一种进位,以便更好地排序

他的回答让我思考……

666 -不要用数字思考- 999

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

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

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

立即用baa和bab符号解决了1.0a和1.0.1排序问题

转换是通过:

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

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

1.0 > > >(“0”,“1”” " ] >>> [ " b”、“”、“”)

为了便于比较,没有必要使用.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正确地解决了这部分挑战。

你可以结合这两种方法:

当涉及字母时,使用.localCompare或versionCompare进行排序

最终的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})) 让v =[" 1.90.1”、“1.090”、“1.0”、“1.0.1”,“1.0.0a”,“1.0.0b”、“1.0.0.1”); console.log (sortVersions (v));