2009-07-25 26 views
25

¿Cómo puedo codificar un número entero con base 36 en Python y luego decodificarlo de nuevo?Python base 36 codificación

+0

posible duplicado de [Cómo convertir un entero a la cadena más corta url-safe en Python?] (http://stackoverflow.com/questions/561486/how-to-convert-an-integer-to-the-shortest-url-safe-string-in-python) – Belldandu

Respuesta

32

¿Has probado el código de muestra de Wikipedia?

def base36encode(number, alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'): 
    """Converts an integer to a base36 string.""" 
    if not isinstance(number, (int, long)): 
     raise TypeError('number must be an integer') 

    base36 = '' 
    sign = '' 

    if number < 0: 
     sign = '-' 
     number = -number 

    if 0 <= number < len(alphabet): 
     return sign + alphabet[number] 

    while number != 0: 
     number, i = divmod(number, len(alphabet)) 
     base36 = alphabet[i] + base36 

    return sign + base36 

def base36decode(number): 
    return int(number, 36) 

print base36encode(1412823931503067241) 
print base36decode('AQF8AA0006EH') 
+18

Cristo si pueden hacer str -> int en cualquier base, pensarías que te dejarían hacer int-> str en cualquier base con un built-in ... – Dubslow

+4

para hacerlo aún más pitónico, agregar la importación de 'string' y reemplazar el valor del alfabeto con' string.digits + string.lowercase' – DataGreed

+1

interfaz entre 'base36encode' y' base36decode' está rota, la última fallará (posiblemente en silencio) para decodificar cualquier cosa codificada w ith argumento 'alphabet' personalizado – Grozz

31

Ojalá hubiera leído esto antes. Aquí está la respuesta:

def base36encode(number): 
    if not isinstance(number, (int, long)): 
     raise TypeError('number must be an integer') 
    if number < 0: 
     raise ValueError('number must be positive') 

    alphabet, base36 = ['ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''] 

    while number: 
     number, i = divmod(number, 36) 
     base36 = alphabet[i] + base36 

    return base36 or alphabet[0] 


def base36decode(number): 
    return int(number, 36) 

print(base36encode(1412823931503067241)) 
print(base36decode('AQF8AA0006EH')) 
+4

Para incluir el alfabeto en minúscula, vea [Cómo convertir un número entero al string más corto seguro para url en Python?] (Http://stackoverflow.com/questions/561486/how-to-convert-an-integer-to-the- shortest-url-safe-string-in-python/561704 # 561704) –

+0

@Tadeck: Porque entonces tiene que invertir 'base36' antes de devolverlo. –

+0

@JohnY: Mi error, eso no sería lo mismo. – Tadeck

9

terribles respuesta, pero fue simplemente jugando con esto un pensamiento que me gustaría compartir.

import string, math 

int2base = lambda a, b: ''.join(
    [(string.digits + string.lowercase + string.uppercase)[(a/b**i)%b] 
    for i in xrange(int(math.log(a, b)), -1, -1)] 
    ) 

num = 1412823931503067241 
test = int2base(num, 36) 
test2 = int(test, 36) 
print test2 == num 
+0

Me gusta bastante, pero tal vez solo tengo una debilidad por el código más corto. –

+4

math.log devuelve un valor flotante de precisión limitada, por lo que se redondean a 14 dígitos antes de truncar la parte fraccionaria. Esto evita convertir 5.999999999999999 en 5.0, por ejemplo. –

+1

math.log() falla cuando a == 0 y su uso es una mierda de todos modos. –

2

Esto funciona si solo te interesan enteros positivos.

def int_to_base36(num): 
    """Converts a positive integer into a base36 string.""" 
    assert num >= 0 
    digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 

    res = '' 
    while not res or num > 0: 
     num, i = divmod(num, 36) 
     res = digits[i] + res 
    return res 

Para convertir de nuevo a int, simplemente use int(num, 36). Para una conversión de bases arbitrarias ver https://gist.github.com/mbarkhau/1b918cb3b4a2bdaf841c

11
from numpy import base_repr 

num = base_repr(num, 36) 
num = int(num, 36) 

Aquí es información sobre numpy.

+0

Intenté mejorar esta respuesta haciéndola ejecutable con datos de ejemplo y agregando más recursos de documentación. La edición fue rechazada por alguna razón con la explicación de que era más adecuada como su propia respuesta. Por lo tanto, he agregado mi versión mejorada de su respuesta a continuación: http://stackoverflow.com/questions/1181919/python-base-36-encoding/42331616#42331616 –

5

Puede usar https://github.com/tonyseek/python-base36.

$ pip install base36 

y luego

>>> import base36 
>>> assert base36.dumps(19930503) == 'bv6h3' 
>>> assert base36.loads('bv6h3') == 19930503 
+1

Esta es la respuesta correcta. No sé por qué todos los demás quieren reinventar la rueda. –

+0

@MichaelScheper Porque las dependencias son difíciles. Ver 'leftpad'. Copiar y pegar una función trivial en un archivo que hace lo que desea a veces es mejor que agregar una nueva dependencia externa. – mbarkhau

+1

@mbarkhau Puede descargar las terceras dependencias a su proveedor de repositorio o su espejo PyPI privado (al igual que los proyectos de Golang). Puede ser mejor que solo copiar y pegar fragmentos de código, para la cobertura de prueba separada y el plan de lanzamiento. –

4

Usted puede utilizar numpy de base_repr(...) para esto.

import numpy as np 

num = 2017 

num = np.base_repr(num, 36) 
print(num) # 1K1 

num = int(num, 36) 
print(num) # 2017 

Aquí hay alguna información sobre numpy, int(x, base=10) y np.base_repr(number, base=2, padding=0).

(Esta respuesta fue presentado originalmente como una edición a la respuesta de @ Christopher-Beland, pero fue rechazado en favor de su propia respuesta.)

Cuestiones relacionadas