web-dev-qa-db-fra.com

Comment comparer le numéro de version du logiciel en utilisant js? (seul numéro)

Voici le numéro de version du logiciel:

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

Comment puis-je comparer ceci ?? Supposons que le bon ordre soit:

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

L'idée est simple ...: Lire le premier chiffre, que, le deuxième, après le troisième .... Mais je ne peux pas convertir le numéro de version en nombre flottant .....__ Vous pouvez également voir le numéro de version comme ceci:

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

et c’est plus clair pour voir quelle est l’idée derrière ... Mais comment le convertir en programme informatique? Je vous remercie. 

134
Tattat

L'idée de base pour effectuer cette comparaison serait d'utiliser Array.split pour obtenir des tableaux de pièces à partir des chaînes d'entrée, puis comparer des paires de pièces des deux tableaux. si les parties ne sont pas égales, nous savons quelle version est la plus petite.

Il y a quelques détails importants à garder à l'esprit:

  1. Comment comparer les pièces de chaque paire? La question veut comparer numériquement, mais que se passe-t-il si nous avons des chaînes de version qui ne sont pas composées uniquement de chiffres (par exemple, "1.0a")?
  2. Que devrait-il se passer si une chaîne de version comporte plus de parties que l'autre? Très probablement, "1.0" devrait être considéré comme inférieur à "1.0.1", mais qu'en est-il de "1.0.0"?

Voici le code pour une implémentation que vous pouvez utiliser directement ( Gist avec documentation ):

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

Cette version compare les parties naturellement , n'accepte pas les suffixes de caractères et considère que "1.7" est inférieur à "1.7.0". Le mode de comparaison peut être changé en lexicographie et les chaînes de version plus courtes peuvent être automatiquement complétées de zéros à l'aide du troisième argument facultatif.

Il existe un JSFiddle qui exécute des "tests unitaires" ici ; c'est une version légèrement développée du travail de ripper234 (merci).

Remarque importante: Ce code utilise Array.map et Array.every , ce qui signifie qu'il ne fonctionnera pas dans les versions IE antérieures à la version 9. Si vous devez les prendre en charge fournir des polyfills pour les méthodes manquantes.

109
Jon

semver

L'analyseur de version sémantique utilisé par 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, '*')

Lien de versioning sémantique
https://www.npmjs.com/package/semver#prerelease-identifiers

51
Mohammed Akdim
// 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"));
45
Joe

Cette fonction de comparaison très petite mais très rapide prend numéros de version de toutes longueurs et tailles de nombres par segment.

Valeurs de retour:
- un nombre < 0 si un <b
- un numéro > 0 si a> b
- 0 si a = b 

Vous pouvez donc l'utiliser comme fonction compare pour Array.sort ();

EDIT: Une version à correction de bug supprimant les zéros à la fin pour reconnaître "1" et "1.0.0" égaux

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

42
LeJared

Extrait de 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;
    }
14
user123444555621

Impossible de trouver une fonction faisant ce que je voulais ici. Alors j'ai écrit le mien. Ceci est ma contribution. J'espère que quelqu'un le trouvera utile.

Avantages:

  • Gère les chaînes de version de longueur arbitraire. "1" ou "1.1.1.1.1".

  • La valeur par défaut de chaque valeur est 0 si non spécifié. Ce n'est pas parce qu'une chaîne est plus longue que c'est une version plus grande. ('1' devrait être identique à '1.0' et '1.0.0.0'.)

  • Comparez les nombres et non les chaînes. ('3' <'21' devrait être vrai. Pas faux.)

  • Ne perdez pas de temps sur des comparaisons inutiles dans la boucle. (En comparant pour ==)

  • Vous pouvez choisir votre propre comparateur.

Les inconvénients:

  • Il ne gère pas les lettres dans la chaîne de version. (Je ne sais pas comment cela pourrait même fonctionner?)

Mon code, similaire à la réponse acceptée par 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);
}

Exemples :

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
8
Viktor

Pardonnez-moi si cette idée a déjà été visitée dans un lien que je n'ai pas vu.

J'ai eu quelques succès avec la conversion des parties en une somme pondérée comme ceci:

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

Ce qui a rendu les comparaisons très faciles (comparer un double) . Nos champs de version ne sont jamais plus de 4 chiffres.

7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0

J'espère que cela aidera quelqu'un, car les multiples conditions préalables semblent un peu excessives.

4
Noxin

Vérifiez la fonction version_compare() du projet php.js . C'est similaire à version_compare() de PHP.

Vous pouvez simplement l'utiliser comme ceci:

version_compare('2.0', '2.0.0.1', '<'); 
// returns true
4
powtac

Réponse 2017:  

v1 = '20.0.12'; 
v2 = '3.123.12';

compareVersion(v1,v2) // return true

function compareVersion(ver1, ver2) {
        ver1 = ver1.split('.')
        ver2 = ver2.split('.')
        var i = 0, v1, v2;
        ver1 = Array.isArray(ver1) ? ver1 : [ver1];
        /*default is true*/
        while (i < 4) {
            v1 = ver1[i]; v2 = ver2[i];
            if (!v1 || !v2) return true;
            if (v1 * 1 < v2 * 1) return false;
            i++;
        }
        return true;
    }

Une réponse plus intéressante pour un navigateur qui ne prend pas en charge IE (lac de padStart) est la suivante: 

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

L'idée ici est de comparer le nombre mais dans le format de chaîne. pour que la comparaison soit juste et facile les deux nombres/chaînes doivent être à la même longueur 

Par exemple:

"123" > "99" // return false, but it wrong "123" "> "099" // but padding the short number with zeros make the comparision to be right

Donc, l’idée de la solution est de remplir toutes les parties de la version avec des zéros afin que tous les nombres aient la même largeur de 10, puis joignent toutes les chaînes. Donc, dans une comparaison pour toute la chaîne, nous obtenons la bonne réponse.

Par exemple :

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
3
pery mimon

Voici une implémentation de coffeescript pouvant être utilisée avec Array.sort, inspirée par d’autres réponses:

# 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
2
LOAS
// 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
    }
2
Dyllan M

Cela fonctionne pour les versions numériques de n'importe quelle longueur séparées par un point. Elle ne renvoie vrai que si myVersion est> = minimumVersion, en supposant que la version 1 est inférieure à 1.0, la version 1.1 est inférieure à 1.1.0 et ainsi de suite. Il devrait être assez simple d’ajouter des conditions supplémentaires telles que accepter des nombres (convertir en chaîne) et hexadécimal ou rendre dynamique le délimiteur (ajoutez simplement un paramètre de délimiteur puis remplacez le "." Par le paramètre)

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

Voici quelques tests:

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

Alternativement voici une version récursive

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);
}
1
Will Schulz

J'ai écrit un module de noeud pour trier les versions, vous pouvez le trouver ici: version-sort

Caractéristiques:

  • pas de limite de séquences '1.0.1.5.53.54654.114.1.154.45' fonctionne
  • pas de limite de longueur de séquence: '1.1546515465451654654654654658134475153364321353734' fonctionne
  • peut trier des objets par version (voir le fichier README)
  • étapes (comme alpha, beta, rc1, rc2)

N'hésitez pas à ouvrir un problème si vous avez besoin d'une autre fonctionnalité.

1
Quentin Rossetti

La fonction replace() ne remplace que la première occurrence de la chaîne. Donc, remplaçons le . par ,. Ensuite, supprimez tout . et réglez le , sur . à nouveau et analysez-le pour qu'il flotte.

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

enfin, le trier:

versions.sort();
1
Sascha Galley

Fonction simple et courte:

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
}

Tests:

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
1
Arthur Araújo

Si, par exemple, nous voulons vérifier si la version actuelle de jQuery est inférieure à 1.8, parseFloat($.ui.version) < 1.8 ) donnera un résultat faux si la version est "1.10.1", car parseFloat ("1.10.1") renvoie 1.1. Une comparaison de chaîne irait également mal, puisque "1.8" < "1.10" est évalué à false.

Nous avons donc besoin d'un test comme celui-ci

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

La fonction suivante gère cela correctement:

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

Voici quelques exemples:

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

Voir ici pour un échantillon live et une suite de tests: http://jsfiddle.net/mar10/8KjvP/

1
mar10

Ma réponse moins verbeuse que la plupart des réponses ici

/**
 * 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
}
1
Ally

Découvrez ce blog post . Cette fonction fonctionne pour les numéros de version numériques. 

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
1
David

L'idée est de comparer deux versions et de savoir laquelle est la plus grande. Nous supprimons "." et nous comparons chaque position du vecteur avec l'autre.

// 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;
      }
   }
}
1
Marc

Voici une autre version courte qui fonctionne avec un nombre quelconque de sous-versions, de zéros et même de chiffres avec lettres (1.0.0b3)

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

Sortie:

0: a = b

1: a> b

-1: a <b

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

0
vanowm

Voici un autre moyen de le faire avec un algorithme récursif.

Ce code utilise uniquement Array.shift et récursif, ce qui signifie qu'il peut s'exécuter dans IE 6+. Si vous avez des doutes, vous pouvez visiter mon 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;
});

J'espère que ces codes aideront quelqu'un. 

Voici les tests.

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
J.G

c'est ma solution. il a accepté sur leetcode. J'ai rencontré le problème dans mon interview aujourd'hui. Mais je ne l’ai pas résolu à ce moment-là… j’y ai repensé. Ajout de zéros pour que la longueur des deux tableaux soit égale. Puis comparaison. 

var compareVersion = function(version1, version2) {
    let arr1 = version1.split('.').map(Number);
    let arr2 = version2.split('.').map(Number);
    let diff = 0;
    if (arr1.length > arr2.length){
        diff = arr1.length - arr2.length;
        while (diff > 0){
            arr2.Push(0);
            diff--;
        } 
    }
    else if (arr1.length < arr2.length){
        diff = arr2.length - arr1.length;
        while (diff > 0){
            arr1.Push(0);
            diff--;
        }
    }
   
    let i = 0;
    while (i < arr1.length){
        if (arr1[i] > arr2[i]){
           return 1;
       } else if (arr1[i] < arr2[i]){
           return -1;
       }
        i++;
    }
    return 0;
    
};

0
metrical1

Je l'ai basé sur l'idée de Kons et l'ai optimisé pour la version Java "1.7.0_45". C'est juste une fonction destinée à convertir une chaîne de version en float. C'est la fonction:

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

La chaîne "1.7.0_45" est convertie en 1.0070000450000001, ce qui est suffisant pour une comparaison normale. Erreur expliquée ici: Comment gérer la précision des nombres en virgule flottante en JavaScript? . Si vous avez besoin de plus de 3 chiffres sur chaque partie, vous pouvez modifier le séparateur Math.pow(10, i * 3);.

La sortie ressemblera à ceci:

1.7.0_45         > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890    > 1.23456789
0
Adrian S

C'est un bon truc. Si vous traitez avec des valeurs numériques, entre une plage de valeurs spécifique, vous pouvez affecter une valeur à chaque niveau de l'objet de version. Par exemple, "plus grande valeur" est défini sur 0xFF ici, ce qui crée une sorte de "adresse IP" pour votre versioning. 

Ceci gère également le versioning alphanumérique (c'est-à-dire 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);
0
Michael Deal

J'aime la version from @ mar10 , bien que de mon point de vue, il y ait un risque d’abus (semble que ce n’est pas le cas si les versions sont compatibles avec Semantic Versioning document, mais peut être le cas si un "numéro de build" est utilisé):

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

Le problème ici est que les sous-numéros de numéro de version sont, dans certains cas, écrits avec des zéros de fin (du moins comme je le vois récemment en utilisant un logiciel différent), ce qui est similaire à la partie rationnelle d'un nombre, ainsi:

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

Toutefois, le premier (ou les deux premier et deuxième) sous-numéros de version est toujours traité comme une valeur entière à laquelle il correspond. 

Si vous utilisez ce type de gestion de version, vous ne pouvez modifier que quelques lignes dans l'exemple:

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

Ainsi, chaque sous-numéro, à l'exception du premier, sera comparé comme un nombre à virgule flottante. Ainsi, 09 et 1 deviendront en conséquence 0.09 et 0.1 et seront comparés correctement de cette façon. 2054 et 3 deviendront 0.2054 et 0.3.

La version complète est donc (crédits à @ 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;
}

P.S. Il est plus lent, mais il est également possible de penser à réutiliser la même fonction de comparaison en exploitant le fait que la chaîne est en réalité le tableau de caractères:

 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;
     }
 }
0
shaman.sir

La fonction retournera -1 si les versions sont égales, 0 si la première version est la dernière et 1 pour indiquer que la deuxième version est la plus récente.

let v1 = '12.0.1.0'
let v2 = '12.0.1'

let temp1 = v1.split('.');
let temp2 = v2.split('.');

console.log(compareVersion(temp1, temp2))


function compareVersion(version1, version2) {
    let flag = false;
    var compareResult;
    let maxLength = Math.max(version1.length, version2.length); 
    let minLength = Math.min(version1.length, version2.length);

    for (let i = 0; i < maxLength; ++i ) {
        let result = version1[i] - version2[i];
        if (result > 0) {
            flag = true;
            compareResult = 0;
            break;
        }
        else if (result < 0) {
            flag = true;
            compareResult = 1;
            break;
        }

        if (i === minLength) {
            if (version1.length > version1.length) {
                compareResult = version1[version1.length-1] > 0 ? '0' : '-1'
            }  else  {
                compareResult = version1[version2.length-1] > 0 ? '1' : '-1'
            }
            break;
        }
    }
    if (flag === false) {
        compareResult = -1;
    }
    return compareResult;
}
0
leox

Ce n’est pas une solution parfaite pour la question posée, mais c’est très similaire.

Cette fonction de tri est destinée aux versions sémantiques , elle gère la version résolue. Elle ne fonctionne donc pas avec les caractères génériques tels que x ou *

Cela fonctionne avec les versions où cette expression régulière correspond: /\d+\.\d+\.\d+.*$/. C'est très similaire à cette réponse sauf que cela fonctionne aussi avec des versions telles que 1.2.3-dev. Comparativement à l'autre réponse: j'ai supprimé des vérifications dont je n'ai pas besoin, mais ma solution peut être combinée avec l'autre un.

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

La solution fusionnée est la suivante:

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

Voici une version qui commande des chaînes de version sans allouer de sous-chaînes ou de tableaux. Étant donné qu’il alloue moins d’objets, le GC a moins de travail à faire.

Il existe une paire d'allocations (pour permettre la réutilisation de la méthode getVersionPart), mais vous pouvez la développer pour éviter les allocations si vous étiez très sensible aux performances.

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
Drew Noakes

Je trouve le moyen le plus simple de les comparer. Je ne sais pas si c'est ce que vous voulez. Quand je lance le code ci-dessous dans la console, cela a du sens, et en utilisant la méthode sort (), je pourrais obtenir le tableau trié des versions. . c'est basé sur l'ordre alphabétique.

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

J'ai eu le même problème de comparaison de version, mais avec des versions contenant éventuellement quelque chose (par exemple: des séparateurs qui n'étaient pas des points, des extensions comme rc1, rc2 ...).

J'ai utilisé ceci, qui divise essentiellement les chaînes de version en nombres et non-nombres, et tente de comparer en fonction du type.

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

Il existe des hypothèses ici pour certains cas, par exemple: "1.01" === "1.1" ou "1.8" <"1.71". Il ne parvient pas à gérer "1.0.0-rc.1" <"1.0.0", comme spécifié par la version 2.0.0 de Semantic

0
Uriel

Le prétraitement des versions antérieures au tri signifie que parseInt n'est pas appelé plusieurs fois inutilement . En utilisant Array # map similaire à la suggestion de Michael Deal, voici un tri que j'utilise pour trouver la dernière version d'un semver standard en 3 parties:

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"

0
theGecko

Une autre implémentation qui mérite d’être partagée, car elle est courte, simple et pourtant puissante. Veuillez noter qu'il utilise uniquement la comparaison de chiffres. Généralement, il vérifie si la version 2 est ultérieure à la version 1 et renvoie true si c'est le cas. Supposons que vous ayez la version 1: 1.1.1 et la version 2: 1.1.2. Il passe en revue chaque partie des deux versions en ajoutant leurs parties comme suit: (1 + 0,1), puis (1.1 + 0.01) pour la version 1 et (1 + 0.1), puis (1.1 + 0.02) pour la version2.

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

Si vous voulez trouver la dernière version de la liste des versions, cela peut être utile:

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
Chris Czopp

ne pourriez-vous pas les convertir en nombres, puis trier selon la taille? Ajouter des 0 à ceux des nombres <4

joué autour de la console: 

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

plus la version est grande, plus le nombre est grand. Edit: a probablement besoin d’être ajusté pour prendre en compte une série plus importante

0
Contra