Quiero escribir una cmp
función -como que compara dos números de versión y retornos -1
, 0
o 1
en base a sus valuses comparación.
- Devolver
-1
si la versión A es anterior a la versión B - Devolver
0
si la versión A y B son equivalentes - Devolver
1
si la versión A es más reciente que la versión B
Se supone que cada subsección debe interpretarse como un número, por lo tanto, 1,10> 1,1.
Las salidas de función deseadas son
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
...
Y aquí está mi implementación, abierta a mejoras:
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
Estoy usando Python 2.4.5 por cierto. (instalado en mi lugar de trabajo ...).
Aquí hay un pequeño 'conjunto de pruebas' que puede usar
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
fuente
fuente
Respuestas:
Elimine la parte no interesante de la cadena (ceros y puntos finales) y luego compare las listas de números.
Este es el mismo enfoque que Pär Wieslander, pero un poco más compacto:
Aquí hay algunas pruebas, gracias a " ¿Cómo comparar dos cadenas en formato de versión separada por puntos en Bash? ":
fuente
rstrip(".0")
cambiará ".10" a ".1" en "1.0.10".¿Qué tal usar Python
distutils.version.StrictVersion
?Entonces, para tu
cmp
función:Si desea comparar números de versión que sean más complejos
distutils.version.LooseVersion
, será más útil, sin embargo, asegúrese de comparar solo los mismos tipos.LooseVersion
no es la herramienta más inteligente y se puede engañar fácilmente:Para tener éxito con esta raza, deberá salir de la biblioteca estándar y utilizar la utilidad de análisis de setuptools
parse_version
.Entonces, dependiendo de su caso de uso específico, deberá decidir si las
distutils
herramientas integradas son suficientes o si se justifica agregar como dependenciasetuptools
.fuente
StrictVersion
SOLO funciona con una versión de hasta tres números. ¡Fracasa en cosas como0.4.3.6
!distribute
en esta respuesta debe reemplazarse porsetuptools
, que viene incluido con elpkg_resources
paquete y tiene desde ... como, siempre . Asimismo, esta es la documentación oficial para lapkg_resources.parse_version()
función incluidasetuptools
.¿Se considera la reutilización como elegancia en este caso? :)
fuente
pkg_resources
es unsetuptools
paquete incluido. Dado quesetuptools
es obligatorio en todas las instalaciones de Python,pkg_resources
está disponible en todas partes. Dicho esto, eldistutils.version
subpaquete también es útil, aunque considerablemente menos inteligente que lapkg_resources.parse_version()
función de nivel superior . Lo que debe aprovechar depende del grado de locura que espera en las cadenas de versiones.setuptools
está fuera de la biblioteca estándar y, en cambio, con mi preferencia declaradadistutils
en este caso . Entonces, ¿qué quiere decir exactamente con "efectivamente obligatorio" y, por favor, puede proporcionar pruebas de que era "efectivamente obligatorio" hace 4,5 años cuando escribí este comentario?No es necesario iterar sobre las tuplas de versión. El operador de comparación integrado en listas y tuplas ya funciona exactamente como lo desea. Solo necesitará extender las listas de versiones a la longitud correspondiente. Con python 2.6 puede usar izip_longest para rellenar las secuencias.
Con versiones inferiores, se requiere algo de piratería de mapas.
fuente
Esto es un poco más compacto que tu sugerencia. En lugar de llenar la versión más corta con ceros, elimino los ceros finales de las listas de versiones después de dividir.
fuente
mycmp
para otros propósitos en su código si lo necesita.Elimine el seguimiento
.0
y.00
con expresiones regulares,split
y use lacmp
función que compara matrices correctamente:Y, por supuesto, puede convertirlo en una sola línea si no le importan las largas colas.
fuente
Es un trazador de líneas (dividido por legibilidad). No estoy seguro de que sea legible ...
fuente
tuple
no es necesario por cierto):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Implementar para php
version_compare
, excepto "=". Porque es ambiguo.fuente
Las listas son comparables en Python, por lo que si alguien convierte las cadenas que representan los números en enteros, la comparación básica de Python puede usarse con éxito.
Necesitaba extender un poco este enfoque porque uso Python3x donde la
cmp
función ya no existe. Tuve que emularcmp(a,b)
con(a > b) - (a < b)
. Y los números de versión no son tan limpios en absoluto, y pueden contener todo tipo de otros caracteres alfanuméricos. Hay casos en los que la función no puede indicar el orden, por lo que regresaFalse
(vea el primer ejemplo).Así que estoy publicando esto incluso si la pregunta es antigua y ya está respondida, porque puede ahorrar algunos minutos en la vida de alguien.
fuente
En caso de que no desee incorporar una dependencia externa, aquí está mi intento escrito para Python 3.x.
rc
,rel
(y posiblemente se podría agregarc
) son considerados como "candidatos de lanzamiento" y dividen el número de versión en dos partes y si falta el valor de la segunda parte es alto (999). Las demás letras producen una división y se tratan como subnúmeros a través del código base 36.fuente
La solución más difícil de leer, ¡pero de una sola línea! y usar iteradores para ser rápido.
eso es para Python2.6 y 3. + por cierto, Python 2.5 y versiones anteriores necesitan capturar la StopIteration.
fuente
Hice esto para poder analizar y comparar la cadena de la versión del paquete Debian. Tenga en cuenta que no es estricto con la validación de caracteres.
Esto también podría ser útil:
fuente
Otra solución:
También se puede usar así:
fuente
estoy usando este en mi proyecto:
fuente
Años más tarde, pero todavía esta pregunta está en la cima.
Aquí está mi función de clasificación de versión. Divide la versión en secciones numéricas y no numéricas. Los números se comparan como
int
restostr
(como parte de los elementos de la lista).Puede usar la función
key
como tipo deVersion
tipo personalizado con operadores de comparación. Si realmente quieres usarlocmp
, puedes hacerlo como en este ejemplo: https://stackoverflow.com/a/22490617/9935708Pasa la suite de pruebas.
fuente
Mi solución preferida:
Rellenar la cadena con ceros adicionales y usar los cuatro primeros es fácil de entender, no requiere ninguna expresión regular y la lambda es más o menos legible. Utilizo dos líneas para facilitar la lectura, para mí la elegancia es breve y simple.
fuente
Esta es mi solución (escrita en C, lo siento). Espero que te sea de utilidad
fuente