Je veux écrire une cmp
fonction -comme qui compare deux numéros de version et les retours -1
, 0
ou en 1
fonction de leur valuses par rapport.
- Renvoie
-1
si la version A est antérieure à la version B - Renvoie
0
si les versions A et B sont équivalentes - Renvoie
1
si la version A est plus récente que la version B
Chaque sous-section est censée être interprétée comme un nombre, donc 1,10> 1,1.
Les sorties de fonction souhaitées sont
mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...
Et voici ma mise en œuvre, ouverte à l'amélioration:
def mycmp(version1, version2):
parts1 = [int(x) for x in version1.split('.')]
parts2 = [int(x) for x in version2.split('.')]
# fill up the shorter version with zeros ...
lendiff = len(parts1) - len(parts2)
if lendiff > 0:
parts2.extend([0] * lendiff)
elif lendiff < 0:
parts1.extend([0] * (-lendiff))
for i, p in enumerate(parts1):
ret = cmp(p, parts2[i])
if ret: return ret
return 0
J'utilise Python 2.4.5 btw. (installé sur mon lieu de travail ...).
Voici une petite `` suite de tests '' que vous pouvez utiliser
assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1
python
string-comparison
Johannes Charra
la source
la source
Réponses:
Supprimez la partie inintéressante de la chaîne (zéros et points de fin), puis comparez les listes de nombres.
C'est la même approche que Pär Wieslander, mais un peu plus compacte:
Voici quelques tests, grâce à " Comment comparer deux chaînes au format de version séparée par des points dans Bash? ":
la source
rstrip(".0")
changera ".10" en ".1" dans "1.0.10".Que diriez-vous d'utiliser Python
distutils.version.StrictVersion
?Donc pour votre
cmp
fonction:Si vous souhaitez comparer des numéros de version plus complexes, ce
distutils.version.LooseVersion
sera plus utile, mais assurez-vous de ne comparer que les mêmes types.LooseVersion
n'est pas l'outil le plus intelligent et peut facilement être trompé:Pour réussir avec cette race, vous devrez sortir de la bibliothèque standard et utiliser l' utilitaire d'analyse de setuptools
parse_version
.Ainsi, en fonction de votre cas d'utilisation spécifique, vous devrez décider si les
distutils
outils intégrés sont suffisants ou s'il est justifié de les ajouter en tant que dépendancesetuptools
.la source
StrictVersion
UNIQUEMENT avec une version à trois chiffres maximum. Cela échoue pour des choses comme0.4.3.6
!distribute
dans cette réponse doit être remplacée parsetuptools
, qui est livré avec lepkg_resources
paquet et a depuis ... comme, jamais . De même, il s'agit de la documentation officielle de lapkg_resources.parse_version()
fonction fournie avecsetuptools
.La réutilisation est-elle considérée comme de l'élégance dans ce cas? :)
la source
pkg_resources
est unsetuptools
package groupé. Depuissetuptools
est effectivement obligatoire sur toutes les installations Python,pkg_resources
est effectivement disponible partout. Cela dit, le sous-distutils.version
paquet est également utile - bien que considérablement moins intelligent que lapkg_resources.parse_version()
fonction de niveau supérieur. Ce que vous devriez exploiter dépend du degré de folie que vous attendez dans les chaînes de version.setuptools
est en dehors de la bibliothèque standard, mais plutôt avec ma préférence déclarée pourdistutils
ce cas . Alors qu'entendez-vous exactement par "effectivement obligatoire", et pouvez-vous fournir la preuve que c'était "effectivement obligatoire" il y a 4,5 ans lorsque j'ai rédigé ce commentaire?Pas besoin d'itérer sur les tuples de version. L'opérateur de comparaison intégré sur les listes et les tuples fonctionne déjà exactement comme vous le souhaitez. Vous aurez juste besoin d'étendre les listes de versions à la longueur correspondante. Avec python 2.6, vous pouvez utiliser izip_longest pour remplir les séquences.
Avec les versions inférieures, un piratage de carte est requis.
la source
C'est un peu plus compact que votre suggestion. Plutôt que de remplir la version plus courte avec des zéros, je supprime les zéros de fin des listes de versions après le fractionnement.
la source
mycmp
à d'autres fins dans votre code si vous en avez besoin.Supprimez la fin
.0
et.00
avec regex,split
et utilisez lacmp
fonction qui compare correctement les tableaux:Et, bien sûr, vous pouvez le convertir en une seule ligne si les longues files d'attente ne vous dérangent pas.
la source
C'est une doublure (séparée pour la lisibilité). Pas sûr de la lisibilité ...
la source
tuple
n'est pas nécessaire btw):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Implémenter pour php
version_compare
, sauf "=". Parce que c'est ambigu.la source
Les listes sont comparables en Python, donc si quelqu'un convertit les chaînes représentant les nombres en entiers, la comparaison de base Python peut être utilisée avec succès.
J'avais besoin d'étendre un peu cette approche car j'utilise Python3x où la
cmp
fonction n'existe plus. J'ai dû émulercmp(a,b)
avec(a > b) - (a < b)
. Et les numéros de version ne sont pas du tout propres et peuvent contenir toutes sortes d'autres caractères alphanumériques. Il y a des cas où la fonction ne peut pas dire l'ordre alors elle retourneFalse
(voir le premier exemple).Donc, je poste ceci même si la question est ancienne et répond déjà, car cela peut gagner quelques minutes dans la vie de quelqu'un.
la source
Au cas où vous ne voudriez pas extraire une dépendance externe, voici ma tentative écrite pour Python 3.x.
rc
,rel
(et éventuellement on pourrait ajouterc
) sont considérés comme "release candidate" et divisent le numéro de version en deux parties et s'il manque la valeur de la deuxième partie est élevée (999). Les autres lettres produisent une division et sont traitées comme des sous-numéros via le code de base 36.la source
La solution la plus difficile à lire, mais néanmoins une ligne! et en utilisant des itérateurs pour être rapide.
c'est-à-dire pour Python2.6 et 3. + btw, Python 2.5 et plus ancien doivent attraper le StopIteration.
la source
J'ai fait cela afin de pouvoir analyser et comparer la chaîne de version du paquet Debian. Veuillez noter que ce n'est pas strict avec la validation des caractères.
Cela pourrait également être utile:
la source
Une autre solution:
On peut utiliser comme ça aussi:
la source
j'utilise celui-ci sur mon projet:
la source
Des années plus tard, mais cette question est toujours au top.
Voici ma fonction de tri de version. Il divise la version en sections numériques et non numériques. Les nombres sont comparés en tant que
int
restestr
(en tant que parties d'éléments de liste).Vous pouvez utiliser la fonction
key
comme type deVersion
type personnalisé avec des opérateurs de comparaison. Si vous voulez vraiment l'utiliser,cmp
vous pouvez le faire comme dans cet exemple: https://stackoverflow.com/a/22490617/9935708La suite de tests réussit.
la source
Ma solution préférée:
Remplir la chaîne avec des zéros supplémentaires et utiliser simplement les quatre premiers est facile à comprendre, ne nécessite aucune expression régulière et le lambda est plus ou moins lisible. J'utilise deux lignes pour la lisibilité, pour moi l'élégance est courte et simple.
la source
C'est ma solution (écrite en C, désolé). J'espère que vous le trouverez utile
la source