Ich möchte einen schreiben cmp
-ähnliche Funktion , die zwei Versionsnummern und kehren vergleicht -1
, 0
oder 1
auf der Grundlage ihres im Vergleich valuses.
- Rückgabe,
-1
wenn Version A älter als Version B ist - Rückgabe,
0
wenn Version A und B gleichwertig sind - Rückgabe,
1
wenn Version A neuer als Version B ist
Jeder Unterabschnitt soll als Zahl interpretiert werden, daher 1.10> 1.1.
Gewünschte Funktionsausgänge sind
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
...
Und hier ist meine Implementierung, die offen für Verbesserungen ist:
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
Ich benutze übrigens Python 2.4.5. (an meinem Arbeitsplatz installiert ...).
Hier ist eine kleine Testsuite, die Sie verwenden können
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
quelle
quelle
Antworten:
Entfernen Sie den uninteressanten Teil der Zeichenfolge (nachgestellte Nullen und Punkte) und vergleichen Sie dann die Zahlenlisten.
Dies ist der gleiche Ansatz wie bei Pär Wieslander, jedoch etwas kompakter:
Hier sind einige Tests dank " Wie vergleiche ich zwei Zeichenfolgen im punktgetrennten Versionsformat in Bash? ":
quelle
rstrip(".0")
wird ".10" in ".1" in "1.0.10" ändern.Wie wäre es mit Pythons
distutils.version.StrictVersion
?Also für Ihre
cmp
Funktion:Wenn Sie komplexere Versionsnummern vergleichen möchten,
distutils.version.LooseVersion
ist dies nützlicher. Vergleichen Sie jedoch nur dieselben Typen.LooseVersion
ist nicht das intelligenteste Werkzeug und kann leicht ausgetrickst werden:Um mit dieser Rasse erfolgreich zu sein, müssen Sie die Standardbibliothek verlassen und das Parsing-Dienstprogramm von setuptools verwenden
parse_version
.Abhängig von Ihrem spezifischen Anwendungsfall müssen Sie entscheiden, ob die integrierten
distutils
Tools ausreichen oder ob das Hinzufügen als Abhängigkeit gerechtfertigt istsetuptools
.quelle
StrictVersion
NUR mit einer Version mit bis zu drei Zahlen funktioniert. Es scheitert an Dingen wie0.4.3.6
!distribute
in dieser Antwort sollte durch ersetzt werdensetuptools
, die impkg_resources
Lieferumfang des Pakets enthalten ist und seitdem ... wie immer . Ebenso ist dies die offizielle Dokumentation für die mitpkg_resources.parse_version()
gebündelte Funktionsetuptools
.Wird Wiederverwendung in diesem Fall als Eleganz angesehen? :) :)
quelle
pkg_resources
ist einsetuptools
gebündeltes Paket. Da diessetuptools
bei allen Python-Installationen effektiv obligatorischpkg_resources
ist , ist es effektiv überall verfügbar. Dasdistutils.version
Unterpaket ist jedoch auch nützlich - wenn auch wesentlich weniger intelligent als die übergeordnetepkg_resources.parse_version()
Funktion. Was Sie nutzen sollten, hängt davon ab, welchen Grad an Wahnsinn Sie in Versionszeichenfolgen erwarten.setuptools
die außerhalb der Standardbibliothek liegt, und stattdessen meinerdistutils
in diesem Fall angegebenen Präferenz für . Was genau meinen Sie mit "effektiv obligatorisch", und können Sie bitte nachweisen, dass es vor 4,5 Jahren "effektiv obligatorisch" war, als ich diesen Kommentar schrieb?Sie müssen die Versionstupel nicht durchlaufen. Der eingebaute Vergleichsoperator für Listen und Tupel funktioniert bereits genau so, wie Sie es möchten. Sie müssen nur die Versionslisten auf Null auf die entsprechende Länge erweitern. Mit Python 2.6 können Sie die Sequenzen mit izip_longest auffüllen.
Bei niedrigeren Versionen ist etwas Kartenhackery erforderlich.
quelle
Dies ist etwas kompakter als Ihr Vorschlag. Anstatt die kürzere Version mit Nullen zu füllen, entferne ich nach dem Teilen nachfolgende Nullen aus den Versionslisten.
quelle
mycmp
für andere Zwecke in Ihrem Code wiederverwenden .Entfernen Sie Trailing
.0
und.00
mit Regexsplit
und verwenden Sie diecmp
Funktion, mit der Arrays korrekt verglichen werden:Und natürlich können Sie es in einen Einzeiler umwandeln, wenn Ihnen die langen Schlangen nichts ausmachen.
quelle
Es ist ein Einzeiler (aus Gründen der Lesbarkeit aufgeteilt). Nicht sicher über lesbar ...
quelle
tuple
wird übrigens nicht benötigt):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Implementiere für PHP
version_compare
, außer "=". Weil es mehrdeutig ist.quelle
Listen sind in Python vergleichbar. Wenn also jemand die Zeichenfolgen, die die Zahlen darstellen, in Ganzzahlen konvertiert, kann der grundlegende Python-Vergleich mit Erfolg verwendet werden.
Ich musste diesen Ansatz etwas erweitern, da ich Python3x verwende, wo die
cmp
Funktion nicht mehr existiert. Ich hatte zu emulierencmp(a,b)
mit(a > b) - (a < b)
. Und Versionsnummern sind überhaupt nicht so sauber und können alle Arten anderer alphanumerischer Zeichen enthalten. Es gibt Fälle, in denen die Funktion die Reihenfolge nicht erkennen kann, sodass sie zurückkehrtFalse
(siehe das erste Beispiel).Ich poste dies auch dann, wenn die Frage alt und bereits beantwortet ist, da dies einige Minuten im Leben eines Menschen sparen kann.
quelle
Für den Fall, dass Sie keine externe Abhängigkeit ziehen möchten, ist hier mein Versuch für Python 3.x geschrieben.
rc
,rel
(und möglicherweise könnte man hinzufügenc
) gelten als "Release Candidate" und teilen die Versionsnummer in zwei Teile und wenn der Wert fehlt, ist der Wert des zweiten Teils hoch (999). Andere Buchstaben erzeugen eine Aufteilung und werden als Subnummern über den Basis-36-Code behandelt.quelle
Die am schwersten zu lesende Lösung, aber dennoch ein Einzeiler! und Iteratoren verwenden, um schnell zu sein.
Das ist für Python2.6 und 3. + Übrigens müssen Python 2.5 und ältere die StopIteration abfangen.
quelle
Ich habe dies getan, um die Versionszeichenfolge des Debian-Pakets analysieren und vergleichen zu können. Bitte beachten Sie, dass die Zeichenvalidierung nicht streng ist.
Dies könnte ebenfalls hilfreich sein:
quelle
Eine andere Lösung:
Man kann auch so verwenden:
quelle
Ich benutze dieses für mein Projekt:
quelle
Jahre später steht diese Frage aber ganz oben.
Hier ist meine Versionssortierfunktion. Die Version wird in Abschnitte mit und ohne Zahlen aufgeteilt. Zahlen werden als
int
Rest wiestr
(als Teile von Listenelementen) verglichen .Sie können die Funktion
key
als eine Art benutzerdefiniertenVersion
Typ mit Vergleichsoperatoren verwenden. Wenn Sie es wirklich verwenden möchten,cmp
können Sie es wie in diesem Beispiel tun: https://stackoverflow.com/a/22490617/9935708Testsuite besteht.
quelle
Meine bevorzugte Lösung:
Das Auffüllen der Zeichenfolge mit zusätzlichen Nullen und die Verwendung der ersten vier ist leicht zu verstehen, erfordert keinen regulären Ausdruck und das Lambda ist mehr oder weniger lesbar. Ich benutze zwei Zeilen für die Lesbarkeit, für mich ist Eleganz kurz und einfach.
quelle
Dies ist meine Lösung (geschrieben in C, sorry). Ich hoffe, Sie finden es nützlich
quelle