Conversión base 62

Resuelto mikl asked hace 15 años • 23 respuestas

¿Cómo convertirías un número entero a base 62 (como hexadecimal, pero con estos dígitos: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

He estado tratando de encontrar una buena biblioteca de Python para ello, pero todas parecen estar ocupadas con la conversión de cadenas. El módulo Python base64 solo acepta cadenas y convierte un solo dígito en cuatro caracteres. Estaba buscando algo parecido a lo que usan los acortadores de URL.

mikl avatar Jul 13 '09 21:07 mikl
Aceptado

No existe un módulo estándar para esto, pero he escrito mis propias funciones para lograrlo.

BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

def encode(num, alphabet):
    """Encode a positive number into Base X and return the string.

    Arguments:
    - `num`: The number to encode
    - `alphabet`: The alphabet to use for encoding
    """
    if num == 0:
        return alphabet[0]
    arr = []
    arr_append = arr.append  # Extract bound-method for faster access.
    _divmod = divmod  # Access to locals is faster.
    base = len(alphabet)
    while num:
        num, rem = _divmod(num, base)
        arr_append(alphabet[rem])
    arr.reverse()
    return ''.join(arr)

def decode(string, alphabet=BASE62):
    """Decode a Base X encoded string into the number

    Arguments:
    - `string`: The encoded string
    - `alphabet`: The alphabet to use for decoding
    """
    base = len(alphabet)
    strlen = len(string)
    num = 0

    idx = 0
    for char in string:
        power = (strlen - (idx + 1))
        num += alphabet.index(char) * (base ** power)
        idx += 1

    return num

Observe el hecho de que puede asignarle cualquier alfabeto para codificar y decodificar. Si omite el alphabetargumento, obtendrá el alfabeto de 62 caracteres definido en la primera línea de código y, por lo tanto, codificará/decodificará a/desde 62 bases.

PD: para los acortadores de URL, he descubierto que es mejor omitir algunos caracteres confusos como 0Ol1oI, etc. Por eso uso este alfabeto para mis necesidades de acortamiento de URL."23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

Baishampayan Ghose avatar Jul 13 '2009 14:07 Baishampayan Ghose

Una vez escribí un guión para hacer esto también, creo que es bastante elegante :)

import string
# Remove the `_@` below for base62, now it has 64 characters
BASE_LIST = string.digits + string.letters + '_@'
BASE_DICT = dict((c, i) for i, c in enumerate(BASE_LIST))

def base_decode(string, reverse_base=BASE_DICT):
    length = len(reverse_base)
    ret = 0
    for i, c in enumerate(string[::-1]):
        ret += (length ** i) * reverse_base[c]

    return ret

def base_encode(integer, base=BASE_LIST):
    if integer == 0:
        return base[0]

    length = len(base)
    ret = ''
    while integer != 0:
        ret = base[integer % length] + ret
        integer /= length

    return ret

Uso de ejemplo:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)
Wolph avatar Mar 30 '2010 23:03 Wolph