Как сравнить номер версии программного обеспечения с помощью 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 ]

1 голос
/ 01 августа 2014

Я написал модуль узла для сортировки версий, вы можете найти его здесь: version-sort

Особенности

  • без ограничений последовательностей '1.0.1.5.53.54654.114.1.154.45' работает
  • без ограничения длины последовательности: '1.1546515465451654654654654138754431574364321353734' работает
  • может сортировать объекты по версии (см. README)
  • этапов (например, альфа, бета, RC1, RC2)

Не стесняйтесь открыть вопрос, если вам нужна другая функция.

0 голосов
/ 25 января 2016

Вот еще один способ сделать это с помощью рекурсивного алгоритма.

Этот код просто использует Array.shift и рекурсивно, что означает, что он может работать в IE 6+ Если у вас есть какие-либо сомнения, вы можете посетить мой 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
0 голосов
/ 26 июля 2011

не могли бы вы преобразовать их в числа, а затем отсортировать по размеру? Добавьте 0 к цифрам, длина которых <4 </p>

поиграл в консоли:

$(["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  )
});

чем больше версия, тем больше число. Редактировать: вероятно, необходимо настроить для учета более крупных версий серии

0 голосов
/ 20 октября 2015

Еще одна реализация, которой я считаю, стоит поделиться, поскольку она короткая, простая и вместе с тем мощная. Обратите внимание, что он использует только сравнение цифр. Обычно он проверяет, является ли версия 2 более поздней, чем версия 1, и возвращает true, если это так. Предположим, у вас есть версия 1: 1.1.1 и версия 2: 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
0 голосов
/ 24 октября 2013

Я сделал это на основе идеи 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 цифр в любой части, вы можете изменить делитель Math.pow(10, i * 3);.

Вывод будет выглядеть так:

1.7.0_45         > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890    > 1.23456789
0 голосов
/ 06 мая 2015
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;
            },
0 голосов
/ 26 июля 2011

Это действительно зависит от логики вашей системы управления версиями . Что представляет собой каждое число и как оно используется.

Является ли каждая подрывная деятельность нумерацией для обозначения стадии разработки? 0 для альфа 1 для бета 2 для освобождения кандидата 3 для (окончательного) выпуска

Это сборочная версия? Применяете ли вы инкрементные обновления?

Как только вы узнаете, как работает система управления версиями, создание алгоритма становится легким.

Если вы не разрешите числа больше 9 в каждой подрывной деятельности, удалив все десятичные дроби, но первое позволит вам сделать прямое сравнение.

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

Но, не зная, как работает система управления версиями, реализация процесса, подобного приведенному выше, может сорваться после выхода версии 1.0.2a.

0 голосов
/ 25 июля 2013

Это хитрый трюк. Если вы имеете дело с числовыми значениями, между определенным диапазоном значений вы можете назначить значение каждому уровню объекта версии. Например, для "largeValue" здесь установлено значение 0xFF, что создает очень "IP" вид вашего контроля версий.

Это также обрабатывает буквенно-цифровые версии (т. Е. 1.2a <1.2b) </p>

// 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);
0 голосов
/ 18 мая 2017

Вот версия, которая упорядочивает строки версий без выделения подстрок или массивов. Поскольку он выделяет меньше объектов, GC выполняет меньше работы.

Существует одна пара выделений (чтобы разрешить повторное использование метода getVersionPart), но вы могли бы расширить это, чтобы вообще избежать выделений, если вы очень чувствительны к производительности.

const compareVersionStrings : (a: string, b: string) => number = (a, b) =>
{
    var ia = {s:a,i:0}, ib = {s:b,i:0};
    while (true)
    {
        var na = getVersionPart(ia), nb = getVersionPart(ib);

        if (na === null && nb === null)
            return 0;
        if (na === null)
            return -1;
        if (nb === null)
            return 1;
        if (na > nb)
            return 1;
        if (na < nb)
            return -1;
    }
};

const zeroCharCode = '0'.charCodeAt(0);

const getVersionPart = (a : {s:string, i:number}) =>
{
    if (a.i >= a.s.length)
        return null;

    var n = 0;
    while (a.i < a.s.length)
    {
        if (a.s[a.i] === '.')
        {
            a.i++;
            break;
        }

        n *= 10;
        n += a.s.charCodeAt(a.i) - zeroCharCode;
        a.i++;
    }
    return n;
}
0 голосов
/ 26 июля 2011

Вот забавный способ сделать это 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...