Eu quero escrever uma cmp
função -como o que compara dois números de versão e retornos -1
, 0
ou 1
com base em suas valuses comparados.
- Retorne
-1
se a versão A for anterior à versão B - Retorne
0
se as versões A e B forem equivalentes - Retorne
1
se a versão A for mais recente que a versão B
Cada subseção deve ser interpretada como um número, portanto 1,10> 1,1.
As saídas da função desejada são
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
...
E aqui está minha implementação, aberta para melhorias:
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
Estou usando o Python 2.4.5 btw. (instalado no meu local de trabalho ...).
Aqui está um pequeno 'conjunto de testes' que você pode 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
fonte
fonte
Respostas:
Remova a parte desinteressante da string (zeros e pontos à direita) e depois compare as listas de números.
Esta é a mesma abordagem de Pär Wieslander, mas um pouco mais compacta:
Aqui estão alguns testes, graças a " Como comparar duas strings no formato de versão separada por pontos no Bash? ":
fonte
rstrip(".0")
mudará de ".10" para ".1" em "1.0.10".Que tal usar o Python
distutils.version.StrictVersion
?Portanto, para sua
cmp
função:Se você quiser comparar números de versão que são mais complexos
distutils.version.LooseVersion
, será mais útil, no entanto, certifique-se de comparar apenas os mesmos tipos.LooseVersion
não é a ferramenta mais inteligente e pode ser facilmente enganada:Para ter sucesso com esta raça, você precisará sair da biblioteca padrão e usar o utilitário de análise do setuptools
parse_version
.Portanto, dependendo do seu caso de uso específico, você precisará decidir se as
distutils
ferramentas integradas são suficientes ou se é necessário adicionar como uma dependênciasetuptools
.fonte
StrictVersion
SOMENTE com uma versão de até três números. Ele falha para coisas como0.4.3.6
!distribute
nesta resposta deve ser substituída porsetuptools
, que vem junto com opkg_resources
pacote e tem desde ... tipo, sempre . Da mesma forma, esta é a documentação oficial para apkg_resources.parse_version()
função incluída no pacotesetuptools
.A reutilização é considerada elegância neste caso? :)
fonte
pkg_resources
é umsetuptools
pacote agrupado. Comosetuptools
é efetivamente obrigatório em todas as instalações do Python,pkg_resources
está efetivamente disponível em qualquer lugar. Dito isso, odistutils.version
subpacote também é útil - embora consideravelmente menos inteligente do que apkg_resources.parse_version()
função de nível superior. O que você deve aproveitar depende do grau de insanidade que você espera nas strings de versão.setuptools
está fora da biblioteca padrão e, em vez disso, da minha preferência declarada pordistutils
neste caso . O que exatamente você quer dizer com "efetivamente obrigatório" e, por favor, você pode fornecer evidências de que era "efetivamente obrigatório" 4,5 anos atrás, quando escrevi este comentário?Não há necessidade de iterar nas tuplas de versão. O operador de comparação embutido em listas e tuplas já funciona exatamente como você deseja. Você só precisa estender de zero as listas de versões para o comprimento correspondente. Com o python 2.6, você pode usar izip_longest para preencher as sequências.
Com versões anteriores, alguns hackeamentos de mapa são necessários.
fonte
Isso é um pouco mais compacto do que sua sugestão. Em vez de preencher a versão mais curta com zeros, estou removendo os zeros à direita das listas de versões após a divisão.
fonte
mycmp
para outros fins em seu código, caso precise.Remova o final
.0
e.00
com regexsplit
e use acmp
função que compara as matrizes corretamente:E, é claro, você pode convertê-lo em uma linha se não se importar com as longas filas.
fonte
É um forro (dividido para legibilidade). Não tenho certeza sobre legível ...
fonte
tuple
não é necessário aliás):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Implemente para php
version_compare
, exceto "=". Porque é ambíguo.fonte
As listas são comparáveis no Python, portanto, se alguém converter as strings que representam os números em inteiros, a comparação básica do Python pode ser usada com sucesso.
Eu precisei estender um pouco essa abordagem porque uso Python3x onde a
cmp
função não existe mais. Eu tive que emularcmp(a,b)
com(a > b) - (a < b)
. E os números de versão não são tão claros e podem conter todos os tipos de outros caracteres alfanuméricos. Há casos em que a função não pode informar a ordem, então ela retornaFalse
(veja o primeiro exemplo).Então estou postando isso mesmo que a pergunta seja antiga e já respondida, pois pode economizar alguns minutos na vida de alguém.
fonte
Caso você não queira obter uma dependência externa, aqui está minha tentativa escrita para Python 3.x.
rc
,rel
(e possivelmente alguém poderia adicionarc
) são considerados "candidatos à liberação" e dividem o número da versão em duas partes e, se estiver faltando, o valor da segunda parte é alto (999). Outras letras produzem uma divisão e são tratadas como subnúmeros por meio do código de base 36.fonte
A solução mais difícil de ler, mas de uma linha! e usar iteradores para ser rápido.
isto é, para Python 2.6 e 3. + btw, Python 2.5 e anteriores precisam capturar a StopIteration.
fonte
Fiz isso para poder analisar e comparar a string de versão do pacote Debian. Observe que não é estrito com a validação de caracteres.
Isso também pode ser útil:
fonte
Outra solução:
Também pode ser usado assim:
fonte
estou usando este no meu projeto:
fonte
Anos depois, mas essa questão ainda está no topo.
Aqui está minha função de classificação de versão. Ele divide a versão em seções de números e não números. Os números são comparados como
int
restantesstr
(como partes de itens da lista).Você pode usar a função
key
como tipo de tipo personalizadoVersion
com operadores de comparação. Se realmente quiser usar,cmp
você pode fazer como neste exemplo: https://stackoverflow.com/a/22490617/9935708O conjunto de testes é aprovado.
fonte
Minha solução preferida:
Preencher a string com zeros extras e usar apenas os quatro primeiros é fácil de entender, não requer nenhuma regex e o lambda é mais ou menos legível. Eu uso duas linhas para facilitar a leitura, para mim a elegância é curta e simples.
fonte
Esta é a minha solução (escrita em C, desculpe). Espero que você ache útil
fonte