Jak porównać numer wersji oprogramowania za pomocą js? (tylko numer)

164

Oto numer wersji oprogramowania:

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"

Jak mogę to porównać? Załóżmy, że prawidłowa kolejność to:

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"

Pomysł jest prosty ...: Przeczytaj pierwszą cyfrę, potem drugą, potem trzecią .... Ale nie mogę przekonwertować numeru wersji na liczbę zmiennoprzecinkową .... Możesz również zobaczyć numer wersji, taki jak to:

"1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1.0"

i to jest bardziej jasne, aby zobaczyć, jaki jest pomysł ... Ale jak przekonwertować go na program komputerowy? Czy ktoś ma pomysł, jak to posortować? Dziękuję Ci.

Tattat
źródło
5
To byłoby dobre pytanie do wywiadu typu bzdury.
Steve Claridge
2
Dlatego wszystkie numery wersji oprogramowania powinny być liczbami całkowitymi, takimi jak 2001403. Jeśli chcesz wyświetlić je w przyjazny sposób, np. „2.0.14.3”, sformatuj numer wersji w czasie prezentacji.
jarmod
2
Ogólnym problemem są tutaj porównania wersji semantycznych i jest on nietrywialny (patrz # 11 na semver.org ). Na szczęście istnieje do tego oficjalna biblioteka, wersja semantyczna dla npm .
Dan Dascalescu
1
Znalazłem prosty skrypt porównujący semvers
vsync

Odpowiedzi:

133

Podstawowym pomysłem wykonania tego porównania byłoby użycie Array.splittablic części z łańcuchów wejściowych, a następnie porównanie par części z dwóch tablic; jeśli części nie są równe, wiemy, która wersja jest mniejsza.

Należy pamiętać o kilku ważnych szczegółach:

  1. Jak porównać części w każdej parze? Pytanie chce porównać numeryczne, ale co, jeśli mamy ciągi wersji, które nie składają się tylko z cyfr (np. „1.0a”)?
  2. Co powinno się stać, jeśli jeden ciąg wersji ma więcej części niż drugi? Najprawdopodobniej „1.0” powinno być uważane za mniejsze niż „1.0.1”, ale co z „1.0.0”?

Oto kod implementacji, którego możesz użyć bezpośrednio ( streszczenie z dokumentacją ):

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

Ta wersja w naturalny sposób porównuje części , nie akceptuje przyrostków znaków i uważa, że ​​„1.7” jest mniejsze niż „1.7.0”. Tryb porównania można zmienić na leksykograficzny, a krótsze ciągi wersji mogą być automatycznie uzupełniane zerami przy użyciu opcjonalnego trzeciego argumentu.

Jest JSFiddle który działa „testy jednostkowe” tutaj ; jest to nieco rozbudowana wersja pracy ripper234 (dziękuję).

Ważna uwaga: ten kod używa Array.mapi Array.every, co oznacza, że ​​nie będzie działał w wersjach IE wcześniejszych niż 9. Jeśli chcesz je obsługiwać, będziesz musiał dostarczyć polifill dla brakujących metod.

Jon
źródło
16
Oto ulepszona wersja z niektórymi testami jednostkowymi: jsfiddle.net/ripper234/Xv9WL/28
ripper234
5
Hej wszystkim, wrzuciłem to streszczenie do gitrepo z testami i wszystkim, i umieściłem to na npm i bower, abym mógł łatwiej włączyć go do moich projektów. github.com/gabe0x02/version_compare
Gabriel Littman
2
@GabrielLittman: Hej, dzięki za poświęcenie czasu na zrobienie tego! Jednak cały kod w SO jest domyślnie objęty licencją CC-BY-SA . Oznacza to, że nie możesz mieć swojego pakietu na licencji GPL. Wiem, że nikt tu nie jest po prawnik, ale byłoby dobrze, gdybyś to naprawił.
Jon
2
@GabrielLittman: GPL jest w rzeczywistości bardzo restrykcyjna w tym sensie, że jesteś zmuszony do udzielenia licencji GPL na cały kod, który ma kontakt z istniejącym kodem GPL. W każdym razie, na przyszłość: dobrą i szeroko stosowaną licencją typu „rób co chcesz, bez zobowiązań” jest MIT .
Jon
3
@GabrielLittman: istnieją już istniejące biblioteki napisane przez doświadczonych programistów, które wykonują porównania semverów.
Dan Dascalescu
82

semver

Parser wersji semantycznej używany przez npm.

$ npm zainstaluj 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, '*')

Łącze do wersjonowania semantycznego :
https://www.npmjs.com/package/semver#prerelease-identifiers

Mohammed Akdim
źródło
8
Tak. To jest poprawna odpowiedź - porównywanie wersji jest nietrywialne (patrz # 11 na semver.org ), a istnieją biblioteki na poziomie produkcyjnym, które wykonują to zadanie.
Dan Dascalescu
7
technicznie rzecz biorąc, to nie są dobre odpowiedzi, ponieważ node.js i javascript są różne. Przypuszczałem, że pierwotne pytanie było bardziej ukierunkowane na przeglądarkę. Ale Google przywiózł mnie tutaj i na szczęście używam node :)
Lee Gary
2
NodeJS to nie tylko rozwiązanie tylko po stronie serwera. Framework Electron osadza nodeJS dla aplikacji desktopowych. To jest odpowiedź, której szukałem.
Anthony Raymond
2
semver to pakiet npm, można go używać na dowolnym środowisku JS! TO jest właściwa odpowiedź
neiker
4
@artuska dobrze po prostu przejść do innego pakietu jak semver-porównać - 233b (mniej niż 0.5kB!) skompresowane:)
Kano
50
// 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"));
Joe
źródło
Myślę, że wiersz: var len = Math.min(a_components.length, b_components.length);spowoduje, że wersje 2.0.1.1 i 2.0.1 będą traktowane tak samo, czy to prawda?
Jon Egerton
1
Nie. Spójrz zaraz po pętli! Jeśli jeden łańcuch jest przedrostkiem drugiego (tj. Pętla osiąga koniec), to dłuższy jest traktowany jako wyższy.
Joe
Być może zniechęciło Cię moje potknięcie się o język angielski w komentarzu ...
Joe
@Joe Wiem, że to trochę stara odpowiedź, ale użyłem tej funkcji. Testowanie a = '7'i b = '7.0'wraca, -1ponieważ wersja 7.0 jest dłuższa. Masz jakąś sugestię? ( console.log(compare("7", "7.0")); //returns -1)
RaphaelDDL
Przypuszczam, że należy to do kategorii niezdefiniowanego zachowania. Jeśli masz te numery wersji, jestem pewien, że możesz zmodyfikować logikę, aby dopasować ją do swoich wymagań.
Joe
48

Ta bardzo mała, ale bardzo szybka funkcja porównywania przyjmuje numery wersji o dowolnej długości i dowolnej wielkości liczbowej na segment .

Wartości zwracane:
- liczba, < 0jeśli a <b
- liczba, > 0jeśli a> b
- 0jeśli a = b

Możesz więc użyć go jako funkcji porównawczej dla Array.sort ();

EDYCJA: Usunięto błędy w wersji usuwającej końcowe zera, aby rozpoznawać „1” i „1.0.0” jako równe

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

LeJared
źródło
Niepowodzenie z „0.0” i „0.0.0”. Zobacz skrzypce: jsfiddle.net/emragins/9e9pweqg
emragins
1
@emragins Kiedy musisz to zrobić?
Skylar Ittner
1
@emragins: Nie wiem, gdzie to się nie powiedzie. Wyprowadza tam, ["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"] gdzie wyprowadza twój kod ["0.0", "0.0.0", "0.4.1", "0.5", "1", "1.0.0", "1.1", "1.2.15", "1.25.4", "2", "2.5.0", "2.5.10", "2.5.10.4159", "10.5"] , co jest całkowicie takie samo, ponieważ 0,0 i 0,0.0 są uważane za równe , co oznacza, że ​​nie ma znaczenia, czy „0,0” jest przed „0,0,0”, czy odwrotnie.
LeJared
Zgadzam się, że to zwykły punkt. Używam tego z github.com/jonmiles/bootstrap-treeview , który warstwuje węzły w sposób podobny do wersji, tylko że tak naprawdę są to tylko węzły nadrzędne / potomne i ich indeksy. Dawny. Rodzic: 0,0, dziecko: 0,0,0, 0,0.1. Zobacz ten numer, aby uzyskać więcej informacji o tym, dlaczego mi zależy: github.com/jonmiles/bootstrap-treeview/issues/251
emragins
1
Zobacz odpowiedź tutaj stackoverflow.com/questions/6611824/why-do-we-need-to-use-radix . Starsze przeglądarki były używane do odgadywania parametru radix, jeśli nie został określony. Początkowe zero w ciągu liczbowym, takie jak środkowa część w "1.09.12", było analizowane z radix = 8, co dało liczbę 0 zamiast oczekiwanej liczby 9.
LeJared
14

Zrobiono z 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;
    }
user123444555621
źródło
Prosty, ale ograniczony do trzech pól wersji.
Dan Dascalescu
11

Nie udało się znaleźć funkcji, która spełniałaby moje oczekiwania. Więc napisałem własne. To mój wkład. Mam nadzieję, że ktoś uzna to za przydatne.

Plusy:

  • Obsługuje ciągi wersji o dowolnej długości. „1” lub „1.1.1.1.1”.

  • Domyślnie każda wartość wynosi 0, jeśli nie zostanie określona. To, że sznurek jest dłuższy, nie oznacza, że ​​jest to większa wersja. („1” powinno być tym samym, co „1.0” i „1.0.0.0”).

  • Porównaj liczby, a nie ciągi. („3” <„21” powinno być prawdą. Nie fałszem).

  • Nie trać czasu na bezużyteczne porównania w pętli. (Porównanie dla ==)

  • Możesz wybrać własny komparator.

Cons:

  • Nie obsługuje liter w ciągu wersji. (Nie wiem, jak to w ogóle działałoby?)

Mój kod, podobny do zaakceptowanej odpowiedzi Jona :

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

Przykłady :

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
Viktor
źródło
ta wersja jest moim zdaniem lepsza niż ta w zatwierdzonej odpowiedzi!
user3807877
1
Ta funkcja jest podatna na wstrzyknięcie kodu, jeśli parametr komparatora jest używany z niezaznaczonymi danymi wejściowymi użytkownika! Przykład: compareVersions ('1.2', '== 0; alert ("cotcha");', '1.2');
LeJared
@LeJared True. Kiedy go napisałem, nie zamierzaliśmy go używać z kodem przesłanym przez użytkownika. Powinienem był potraktować to jako oszustwo. Zaktualizowałem kod, aby wyeliminować tę możliwość. Teraz jednak, kiedy webpack i inne bundlery node.js stały się powszechne, sugerowałbym, że powyższa odpowiedź Mohammeda Akdima , używając semver, prawie zawsze byłaby poprawną odpowiedzią na to pytanie.
Viktor
10

Prosta i krótka funkcja:

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
}

Testy:

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
Arthur Araújo
źródło
Możesz to uprościć: const a = ~~ newParts [i]; W rzeczywistości jest to najbardziej efektywny sposób konwersji ciągu znaków na liczbę całkowitą, która zwraca 0, jeśli zmienna jest niezdefiniowana lub zawiera znaki nienumeryczne.
vanowm
5

Wybacz mi, jeśli ten pomysł był już odwiedzony w linku, którego nie widziałem.

Odniosłem pewien sukces przy zamianie części na sumę ważoną, taką jak:

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

Co sprawiło, że porównania były bardzo łatwe (porównywanie podwójnego). Nasze pola wersji nigdy nie mają więcej niż 4 cyfry.

7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0

Mam nadzieję, że to komuś pomoże, ponieważ wiele warunków wydaje się nieco przesadzone.

Noxin
źródło
2
To złamać czy this.minor> 999 (pokrywają się z głównymi)
Afanasii Kurakin
5

Oto kolejna krótka wersja, która działa z dowolną liczbą podwersji, wypełnionych zer, a nawet cyfr z literami (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;
}

Wynik:

0 : a = b

1 : a> b

-1 : a <b

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

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

vanowm
źródło
5

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

Najprostszy kod dla nowoczesnych przeglądarek:

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

Chodzi o to, aby porównać liczby, ale w formie ciągu. aby porównanie działało, dwa struny muszą być tej samej długości. więc:

"123" > "99"staje się "123" > "099"
wypełnieniem krótkiej liczby "napraw" porównanie

Tutaj dopełniam każdą część zerami do długości 10., a następnie po prostu używam prostego porównania ciągów do odpowiedzi

Przykład:

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
pery mimon
źródło
czy mógłbyś wyjaśnić funkcję, compareVersion2co dokładnie się stało?
Usman Wali
Dobra, a następnie można użyć substringzamiast padStartdla lepszej kompatybilności tj var zeros = "0000000000"; '0.2.32'.split('.').map( s => zeros.substring(0, zeros.length-s.length) + s ).join('.') da wam 0000000000.0000000002.0000000032:)
Usman Wali
4

Moja mniej szczegółowa odpowiedź niż większość odpowiedzi tutaj

/**
 * 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
}
Sprzymierzyć
źródło
1
powinieneś zrobić z niego moduł i umieścić go na node.js. do tego czasu kradnę Twój kod z przypisaniem do Ciebie. Dziękuję Ci za to.
r3wt
3

Chociaż to pytanie ma już wiele odpowiedzi, każde z nich promuje swoje własne rozwiązanie, podczas gdy mamy do tego cały ekosystem (w bitwach) przetestowanych bibliotek.

Szybkie wyszukiwanie w NPM , GitHub , X da nam kilka uroczych bibliotek i chciałbym przejrzeć niektóre:

semver-compareJest to świetny lekki (~ 230B) lib to szczególnie przydatne, jeśli chcesz, aby posortować według numerów wersji, jako narażonych zwrotów metoda biblioteki -1, 0lub 1odpowiednio.

Rdzeń biblioteki:

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

compare-semver ma dość spory rozmiar (~ 4,4kB spakowane gzipem), ale pozwala na kilka ładnych, unikalnych porównań, takich jak znalezienie min / max stosu wersji lub sprawdzenie, czy dostarczona wersja jest unikalna lub mniejsza niż cokolwiek innego w kolekcji wersje.

compare-versionsto kolejna mała biblioteka (~ 630B spakowana gzipem) i ładnie podąża za specyfikacją, co oznacza, że ​​możesz porównać wersje z flagami alfa / beta, a nawet z symbolami wieloznacznymi (jak dla wersji pomocniczych / łatek: 1.0.xlub 1.0.*)

Chodzi o to: nie zawsze istnieje potrzeba kopiowania i wklejania kodu ze StackOverflow, jeśli możesz znaleźć przyzwoite, przetestowane (jednostkowo) wersje za pośrednictwem wybranego menedżera pakietów.

kano
źródło
3

Zmierzyłem się z podobnym problemem i już stworzyłem na to rozwiązanie. Zapraszam do spróbowania.

Wraca 0po equal, 1jeśli wersja jest greateri -1jeśli jestless

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

Awesome Dev
źródło
2

Chodzi o to, aby porównać dwie wersje i wiedzieć, która jest największa. Usuwamy „.” i porównujemy każdą pozycję wektora z innymi.

// 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;
      }
   }
}
Marc
źródło
Epicka odpowiedź, dokładnie to, czego szukałem.
Vince
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
    }
Dyllan M
źródło
1
Witamy w SO. To pytanie ma już wiele dobrych odpowiedzi, powstrzymaj się od dodawania nowych odpowiedzi, chyba że dodasz coś nowego.
ext
1

replace()Funkcja zastąpi tylko pierwsze wystąpienie w ciągu. Tak, pozwala zastąpić .z ,. Potem usunąć wszystko .i zrobić ,aby .ponownie i analizować je do pływaka.

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

na koniec posortuj to:

versions.sort();
Sascha Galley
źródło
1

Sprawdź ten wpis na blogu . Ta funkcja działa dla numerycznych numerów wersji.

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
David
źródło
1

Jeśli, na przykład, chcemy sprawdzić, czy aktualna wersja jQuery jest niższa niż 1.8, parseFloat($.ui.version) < 1.8 )dałoby to błędny wynik, jeśli wersja to "1.10.1", ponieważ zwraca parseFloat ("1.10.1") 1.1. Porównanie ciągów również by się nie udało, ponieważ "1.8" < "1.10"wartościowane są do false.

Więc potrzebujemy takiego testu

if(versionCompare($.ui.version, "1.8") < 0){
    alert("please update jQuery");
}

Następująca funkcja obsługuje to poprawnie:

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

Oto kilka przykładów:

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

Zobacz tutaj próbkę na żywo i zestaw testów: http://jsfiddle.net/mar10/8KjvP/

mar10
źródło
arghh, właśnie zauważyłem, że ripper234 zamieścił skrzypcowy adres URL w ez komentarzy kilka miesięcy temu, który jest dość podobny. W każdym razie, moja odpowiedź jest tutaj ...
marca
Ten również zawiedzie (jak większość innych wariantów) w tych przypadkach: versionCompare ('1.09', '1.1') zwraca "1", tak samo jak versionCompare ('1.702', '1.8').
shaman.sir
Kod ocenia „1,09”> „1,1” i „1,702”> „1,8”, co moim zdaniem jest poprawne. Jeśli się nie zgadzasz: czy możesz wskazać jakieś źródło, które potwierdza Twoją opinię?
mar10
To zależy od twoich zasad - wiem, że nie ma żadnej ścisłej reguły. Jeśli chodzi o zasoby, artykuł Wikipedii dla "Wersjonowanie oprogramowania" w "Sekwencje przyrostowe" mówi, że 1.81 może być mniejszą wersją 1.8, więc 1.8 powinno być czytane jako 1.80. W artykule o wersjonowaniu semantycznym semver.org/spec/v2.0.0.html podano również, że 1.9.0 -> 1.10.0 -> 1.11.0, więc 1.9.0 jest traktowane jako 1.90.0 w porównaniu z tym. Tak więc, zgodnie z tą logiką, wersja 1.702 była wcześniejsza niż wersja 1.8, która jest traktowana jako 1.800.
shaman.sir
1
Widzę, że niektóre zasady traktują 1,8 <1,81 <1,9. Ale w semver użyłbyś 1.8.1 zamiast 1.81. Semver (jak rozumiem) jest zdefiniowany w oparciu o założenie, że inkrementacja części zawsze generuje „późniejszą” wersję, więc 1.8 <1.8.1 <1.9 <1,10 <1.81 <1.90 <1.100. Nie widzę wskazania, że ​​jest to również ograniczone do dwóch cyfr. Więc powiedziałbym, że mój kod jest w pełni zgodny z semver.
mar10
1

Oto implementacja Coffeescript odpowiednia do użycia z Array.sort inspirowana innymi odpowiedziami tutaj:

# 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
LOAS
źródło
Inspiruje to odpowiedź LeJareda .
Dan Dascalescu
to nie działa prawidłowo .. oto wynik .. result ['1.1.1', '2.1.1', '3.3.1.0', '3.1.1.0']
ertan2002
1

Napisałem moduł node do sortowania wersji, możesz go znaleźć tutaj: version-sort

Cechy :

  • bez limitu sekwencji działa „1.0.1.5.53.54654.114.1.154.45”
  • bez limitu długości sekwencji: działa „1.1546515465451654654654654138754431574364321353734”
  • może sortować obiekty według wersji (zobacz README)
  • etapy (takie jak alfa, beta, rc1, rc2)

Nie wahaj się otworzyć problemu, jeśli potrzebujesz innej funkcji.

Quentin Rossetti
źródło
1

Działa to w przypadku wersji numerycznych o dowolnej długości oddzielonych kropką. Zwraca wartość true tylko wtedy, gdy myVersion jest> = minimumVersion, przy założeniu, że wersja 1 jest mniejsza niż 1.0, wersja 1.1 jest mniejsza niż 1.1.0 i tak dalej. Powinno być dość proste, aby dodać dodatkowe warunki, takie jak akceptowanie liczb (po prostu przekonwertowanie na ciąg) i szesnastkowe lub dynamiczne wprowadzanie separatora (wystarczy dodać parametr delimiter, a następnie zastąpić „.” Parametrem).

function versionCompare(myVersion, minimumVersion) {

    var v1 = myVersion.split("."), v2 = minimumVersion.split("."), minLength;   

    minLength= Math.min(v1.length, v2.length);

    for(i=0; i<minLength; i++) {
        if(Number(v1[i]) > Number(v2[i])) {
            return true;
        }
        if(Number(v1[i]) < Number(v2[i])) {
            return false;
        }           
    }

    return (v1.length >= v2.length);
}

Oto kilka testów:

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

Alternatywnie tutaj jest wersja rekurencyjna

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);
}
Will Schulz
źródło
1

Znajduję najprostszy sposób na ich porównanie, nie jestem pewien, czy tego chcesz. kiedy uruchomię poniższy kod w konsoli, ma to sens, a używając metody sort (), mogłem uzyskać posortowaną tablicę ciągów wersji. jest oparty na porządku alfabetycznym.

"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"]
po co
źródło
3
Nie działa dobrze w przypadku dwucyfrowych numerów wersji, np. 1.10.0.
Leukipp
1

Możesz użyć String#localeComparezoptions

wrażliwość

Jakie różnice w łańcuchach powinny prowadzić do niezerowych wartości wyników. Możliwe wartości to:

  • "base": Tylko łańcuchy różniące się literami podstawowymi są porównywane jako nierówne. Przykłady: a ≠ b, a = á, a = A.
  • "accent": Tylko ciągi różniące się podstawowymi literami lub akcentami i innymi znakami diakrytycznymi są traktowane jako nierówne. Przykłady: a ≠ b, a ≠ á, a = A.
  • "case": Tylko łańcuchy różniące się literami podstawowymi lub wielkością liter są porównywane jako nierówne. Przykłady: a ≠ b, a = á, a ≠ A.
  • "variant": Ciągi znaków różniące się podstawowymi literami, akcentami i innymi znakami diakrytycznymi lub porównaniem wielkości liter jako nierówne. Można również wziąć pod uwagę inne różnice. Przykłady: a ≠ b, a ≠ á, a ≠ A.

Wartość domyślna to „wariant” dla użycia „sort”; jest zależne od lokalizacji dla użycia „szukaj”.

numeryczny

Określa, czy należy stosować sortowanie numeryczne, np. „1” <„2” <„10”. Możliwe wartości to truei false; wartość domyślna to false. Tę opcję można ustawić za pomocą właściwości options lub klucza rozszerzenia Unicode; jeśli podano oba, optionswłaściwość ma pierwszeństwo. Implementacje nie są wymagane do obsługi tej właściwości.

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

Nina Scholz
źródło
Jak to właściwie działa? Co to jest undefinedpowyżej, język? Jak to się stało, że udaje ci się to opublikować, a ja czytam inne;)
mplungjan
undefinedto część dotycząca ustawień regionalnych, nie jest tutaj używana.
Nina Scholz
0

czy nie możesz zamienić ich na liczby, a następnie posortować według rozmiaru? Dołącz 0 do jedynek do liczb o długości mniejszej niż 4

grane w konsoli:

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

większa wersja, większa liczba. Edycja: prawdopodobnie wymaga dostosowania, aby uwzględnić większą serię wersji

Contra
źródło
To był tylko przykład, ponieważ musi zrobić kilka rzeczy sam: P Zamiast 4, weź liczbę liczb, które ma największa wersja, a następnie wypełnij te niższe
zerami
0

To niezła sztuczka. Jeśli masz do czynienia z wartościami liczbowymi z określonego zakresu wartości, możesz przypisać wartość do każdego poziomu obiektu wersji. Na przykład „największa wartość” jest tutaj ustawiana na 0xFF, co tworzy bardzo podobny wygląd „IP” do wersjonowania.

Obsługuje również wersje alfanumeryczne (tj. 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);
Michael Deal
źródło
0

Podoba mi się wersja z @ mar10 , chociaż z mojego punktu widzenia jest szansa na niewłaściwe użycie (wydaje się, że nie ma to miejsca, jeśli wersje są kompatybilne z dokumentem wersjonowania semantycznego , ale może się zdarzyć, jeśli zostanie użyty jakiś "numer kompilacji" ):

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

Problem polega na tym, że podliczby numeru wersji są w niektórych przypadkach zapisywane z wyciętymi końcowymi zerami (przynajmniej tak, jak widzę to ostatnio podczas korzystania z innego oprogramowania), co jest podobne do racjonalnej części liczby, więc:

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

Pierwsza (lub zarówno pierwsza, jak i druga) liczba podrzędna wersji jest jednak zawsze traktowana jako liczba całkowita, której faktycznie jest równa.

Jeśli używasz tego rodzaju wersjonowania, możesz zmienić tylko kilka wierszy w przykładzie:

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

Więc każdy sub-number wyjątkiem pierwszego będzie porównywany jako pływaka, tak 09i 1będzie 0.09, a 0.1odpowiednio i porównywane prawidłowo w ten sposób. 2054i 3stanie się 0.2054i 0.3.

Pełna wersja to (kredyty dla @ 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;
}

PS Jest wolniej, ale można też pomyśleć o ponownym użyciu tej samej funkcji porównującej operującej faktem, że łańcuch jest w rzeczywistości tablicą znaków:

 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;
     }
 }
szaman.sir
źródło
0

Zrobiłem to na podstawie pomysłu Konsola i zoptymalizowałem dla wersji Java "1.7.0_45". Jest to po prostu funkcja przeznaczona do konwersji ciągu wersji na wartość zmiennoprzecinkową. To jest funkcja:

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

Ciąg „1.7.0_45” jest konwertowany na 1,0070000450000001 i jest to wystarczające do normalnego porównania. Błąd wyjaśniony tutaj: Jak radzić sobie z precyzją liczb zmiennoprzecinkowych w JavaScript? . Jeśli potrzebujesz więcej niż 3 cyfr w dowolnej części, możesz zmienić separator Math.pow(10, i * 3);.

Wynik będzie wyglądał następująco:

1.7.0_45         > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890    > 1.23456789
Adrian S.
źródło
0

Miałem ten sam problem z porównaniem wersji, ale z wersjami mogącymi zawierać cokolwiek (tj: separatory, które nie były kropkami, rozszerzenia takie jak rc1, rc2 ...).

Użyłem tego, co w zasadzie podzieliło ciągi wersji na liczby i nieliczby, i próbuje porównać odpowiednio do typu.

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

W niektórych przypadkach istnieją pewne założenia, na przykład: „1,01” === „1,1” lub „1,8” <„1,71”. Nie radzi sobie z „1.0.0-rc.1” <„1.0.0”, jak określono w Semantic versionning 2.0.0

Uriel
źródło
0

Wstępne przetwarzanie wersji przed sortowaniem oznacza, że ​​parseInt nie jest wywoływana wiele razy niepotrzebnie. Używając mapy Array # podobnej do sugestii Michaela Deala, oto rodzaj, którego używam, aby znaleźć najnowszą wersję standardowego 3-częściowego semvera:

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"

theGecko
źródło