Chcę napisać cmp
-Jak funkcję, która porównuje dwa numery wersji i zwrotów -1
, 0
albo 1
na podstawie ich stosunku valuses.
- Zwróć,
-1
jeśli wersja A jest starsza niż wersja B. - Zwróć,
0
jeśli wersje A i B są równoważne - Zwróć,
1
jeśli wersja A jest nowsza niż wersja B.
Każda podsekcja ma być interpretowana jako liczba, dlatego 1,10> 1,1.
Wymagane wyjścia funkcji to
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
...
A oto moja implementacja, otwarta na ulepszenia:
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
Przy okazji używam Pythona 2.4.5. (zainstalowany w moim miejscu pracy ...).
Oto mały „zestaw testów”, którego możesz użyć
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
źródło
źródło
Odpowiedzi:
Usuń nieciekawą część ciągu (końcowe zera i kropki), a następnie porównaj listy liczb.
To jest to samo podejście, co Pär Wieslander, ale nieco bardziej zwarte:
Oto kilka testów dzięki „ Jak porównać dwa ciągi znaków w formacie wersji rozdzielanej kropkami w Bash? ”:
źródło
rstrip(".0")
zmieni się „.10” na „.1” w „1.0.10”.A co powiesz na używanie Pythona
distutils.version.StrictVersion
?Więc dla twojej
cmp
funkcji:Jeśli chcesz porównać numery wersji, które są bardziej złożone,
distutils.version.LooseVersion
będą bardziej przydatne, jednak pamiętaj, aby porównać tylko te same typy.LooseVersion
nie jest najbardziej inteligentnym narzędziem i można go łatwo oszukać:Aby odnieść sukces z tą rasą, musisz wyjść poza standardową bibliotekę i użyć narzędzia do parsowania setuptools
parse_version
.W zależności od konkretnego przypadku użycia, musisz zdecydować, czy wbudowane
distutils
narzędzia są wystarczające, czy też uzasadnione jest dodanie jako zależnościsetuptools
.źródło
StrictVersion
TYLKO z wersją do trzech numerów. Nie udaje się na przykład0.4.3.6
!distribute
w tej odpowiedzi powinno zostać zastąpione przezsetuptools
, który jest dostarczany wpkg_resources
pakiecie i od tego czasu ... jak zawsze . Podobnie, jest to oficjalna dokumentacja dlapkg_resources.parse_version()
funkcji w pakiecie zsetuptools
.Czy ponowne użycie jest w tym przypadku uważane za elegancję? :)
źródło
pkg_resources
jestsetuptools
pakietem w pakiecie. Ponieważsetuptools
jest obowiązkowe we wszystkich instalacjach Pythona,pkg_resources
jest efektywnie dostępne wszędzie. To powiedziawszy,distutils.version
podpakiet jest również przydatny - choć znacznie mniej inteligentny niż funkcja wyższego poziomupkg_resources.parse_version()
. To, które powinieneś wykorzystać, zależy od tego, jakiego stopnia szaleństwa oczekujesz od ciągów wersji.setuptools
znajduje się w standardowej bibliotece, a zamiast tego z moją deklarowaną preferencjądistutils
w tym przypadku . Więc co dokładnie rozumiesz przez „skutecznie obowiązkowe” i czy możesz przedstawić dowody, że było to „faktycznie obowiązkowe” 4,5 roku temu, kiedy pisałem ten komentarz?Nie ma potrzeby iteracji po krotkach wersji. Wbudowany operator porównania na listach i krotkach już działa dokładnie tak, jak chcesz. Wystarczy zerować, aby rozszerzyć listy wersji do odpowiedniej długości. W Pythonie 2.6 możesz użyć izip_longest do wypełnienia sekwencji.
W przypadku niższych wersji wymagane jest trochę hakowania map.
źródło
To jest trochę bardziej zwięzłe niż twoja sugestia. Zamiast wypełniać krótszą wersję zerami, usuwam końcowe zera z list wersji po podzieleniu.
źródło
mycmp
do innych celów w swoim kodzie, jeśli tego potrzebujesz.Usuń końcowe
.0
i.00
z wyrażeniem regularnymsplit
i użyjcmp
funkcji, która poprawnie porównuje tablice:I oczywiście możesz przekształcić go w jednolinijkowy, jeśli nie przeszkadzają ci długie linie.
źródło
To jedna wkładka (podzielona dla czytelności). Nie jestem pewien co do czytelności ...
źródło
tuple
okazji nie jest potrzebny):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Zaimplementuj dla php
version_compare
, z wyjątkiem „=”. Ponieważ jest niejednoznaczne.źródło
Listy są porównywalne w Pythonie, więc jeśli ktoś zamieni ciągi reprezentujące liczby na liczby całkowite, z powodzeniem można zastosować podstawowe porównanie Pythona.
Musiałem nieco rozszerzyć to podejście, ponieważ używam Python3x, w którym
cmp
funkcja już nie istnieje. Musiałem naśladowaćcmp(a,b)
z(a > b) - (a < b)
. Numery wersji nie są wcale takie czyste i mogą zawierać wszelkiego rodzaju inne znaki alfanumeryczne. Są przypadki, gdy funkcja nie może podać kolejności, więc zwracaFalse
(zobacz pierwszy przykład).Więc piszę to, nawet jeśli pytanie jest stare i już odpowiedziałem, bo może to zaoszczędzić kilka minut w czyimś życiu.
źródło
Jeśli nie chcesz wciągać zewnętrznej zależności, oto moja próba napisana dla Pythona 3.x.
rc
,rel
(i być może można by dodaćc
) są uważane za „kandydatów do wydania” i dzielą numer wersji na dwie części, a jeśli ich brakuje, wartość drugiej części jest wysoka (999). W przeciwnym razie litery powodują podział i są traktowane jako liczby podrzędne za pośrednictwem kodu base-36.źródło
Najtrudniejsze do odczytania rozwiązanie, ale jednak jednolinijkowe! i używając iteratorów, aby działać szybko.
to jest dla Python2.6 i 3. + btw, Python 2.5 i starsze muszą przechwytywać StopIteration.
źródło
Zrobiłem to, aby móc przeanalizować i porównać ciąg znaków wersji pakietu Debiana. Proszę zauważyć, że nie jest to ścisłe przy sprawdzaniu poprawności znaków.
Może to być również pomocne:
źródło
Inne rozwiązanie:
Można też użyć w ten sposób:
źródło
używam tego w moim projekcie:
źródło
Wiele lat później, ale nadal to pytanie jest na topie.
Oto moja funkcja sortowania wersji. Dzieli wersję na sekcje liczbowe i nieliczbowe. Liczby są porównywane z
int
resztą jakostr
(jako części elementów listy).Funkcji można używać
key
jako typu niestandardowegoVersion
z operatorami porównania. Jeśli naprawdę chcesz skorzystaćcmp
, możesz to zrobić jak w tym przykładzie: https://stackoverflow.com/a/22490617/9935708Pakiet testów przechodzi pomyślnie.
źródło
Moje preferowane rozwiązanie:
Uzupełnienie łańcucha dodatkowymi zerami i użycie samych czterech pierwszych jest łatwe do zrozumienia, nie wymaga żadnego wyrażenia regularnego, a lambda jest mniej lub bardziej czytelna. Dla czytelności używam dwóch linijek, dla mnie elegancja jest krótka i prosta.
źródło
To jest moje rozwiązanie (napisane w C, przepraszam). Mam nadzieję, że okażą się przydatne
źródło