J'aime la version de @ mar10 , bien que de mon point de vue, il y ait un risque d'utilisation abusive (il semble que ce ne soit pas le cas si les versions sont compatibles avec le document de version sémantique , mais cela 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 du numéro de version sont, dans certains cas, écrits avec des zéros de fin coupés (du moins comme je le vois récemment en utilisant un logiciel différent), ce qui est similaire à la partie rationnelle d'un nombre, donc:
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
Le premier (ou les deux premier et deuxième) sous-numéro de version, cependant, est toujours traité comme une valeur entière à laquelle il est en fait égal.
Si vous utilisez ce type de gestion des versions, vous pouvez modifier 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-nombre sauf le premier sera comparé comme un flottant, ainsi 09
et 1
deviendra 0.09
et en 0.1
conséquence et comparé correctement de cette façon. 2054
et 3
deviendra 0.2054
et0.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;
}
PS Il est plus lent, mais aussi possible de penser à réutiliser la même fonction de comparaison en opérant le fait que la chaîne est en fait 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;
}
}