Как сравнить номер версии программного обеспечения с помощью js? (только номер) - PullRequest
142 голосов
/ 26 июля 2011

Вот номер версии программного обеспечения:

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

и это более ясно, чтобы понять, в чем идея ... Но как преобразовать его в компьютерную программу? У кого-нибудь есть идеи о том, как это отсортировать? Спасибо.

Ответы [ 38 ]

115 голосов
/ 26 июля 2011

Основная идея для такого сравнения заключается в использовании Array.split для получения массивов деталей из входных строк, а затем сравнения пар деталей из двух массивов;если части не равны, мы знаем, какая версия меньше.

Есть несколько важных деталей, о которых следует помнить:

  1. Как следует сравнивать части в каждой паре?Вопрос хочет сравнить численно, но что если у нас есть строки версий, которые не состоят только из цифр (например, «1.0a»)?
  2. Что должно произойти, если одна строка версии имеет больше частей, чем другая?Скорее всего, «1.0» следует считать меньше, чем «1.0.1», но как насчет «1.0.0»?

Вот код для реализации, которую вы можете использовать напрямую ( gistс документацией ):

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.map и Array.every, что означает, что он не будет работать в версиях IE более ранних, чем 9. Если вам потребуется их поддержка, вам придется предоставить полифиллы для отсутствующих методов.

57 голосов
/ 15 мая 2015

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

47 голосов
/ 26 июля 2011
// 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"));
42 голосов
/ 24 апреля 2013

Эта очень маленькая, но очень быстрая функция сравнения принимает номера версий любой длины и любого размера числа на сегмент .

Возвращаемые значения:
- число < 0, если a - число > 0, если a> b
- 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"]
14 голосов
/ 26 июля 2011

Взято из 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;
    }
8 голосов
/ 20 ноября 2013

Не удалось найти функцию, выполняющую то, что я хотел здесь. Поэтому я написал свой. Это мой вклад. Я надеюсь, что кто-то найдет это полезным.

Плюсы:

  • Обрабатывает строки версии произвольной длины. «1» или «1.1.1.1.1».

  • По умолчанию каждое значение равно 0, если не указано. То, что строка длиннее, не означает, что она больше. («1» должно совпадать с «1.0» и «1.0.0.0».)

  • Сравните числа, а не строки. («3» <«21» должно быть истинным. Не ложным.) </p>

  • Не тратьте время на бесполезные сравнения в цикле. (Для сравнения ==)

  • Вы можете выбрать свой собственный компаратор.

Минусы:

  • Он не обрабатывает буквы в строке версии. (Я не знаю, как это будет работать?)

Мой код, похожий на принятый ответ 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
4 голосов
/ 07 ноября 2015

Простите, если эту идею уже посещали по ссылке, которую я не видел.

У меня был некоторый успех с преобразованием частей в взвешенную сумму, например, так:

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

Надеюсь, это кому-нибудь поможет, так как несколько условных выражений кажутся немного излишними.

4 голосов
/ 26 июля 2011

Проверьте функцию version_compare() из проекта php.js . Это похоже на PHP version_compare().

Вы можете просто использовать его так:

version_compare('2.0', '2.0.0.1', '<'); 
// returns true
3 голосов
/ 28 августа 2018

Простая и короткая функция:

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
3 голосов
/ 20 ноября 2018

Вот еще одна короткая версия, которая работает с любым количеством подверсий, дополненных нулями и четными числами с буквами (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/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...