python - online - text to base64
Conversión Base 62 (18)
Ahora hay una biblioteca de Python para esto.
Estoy trabajando en hacer un paquete de pip para esto.
Te recomiendo que uses mi base.py https://github.com/kamijoutouma/bases.py que fue inspirado por bases.js
from bases import Bases
bases = Bases()
bases.toBase16(200) // => ''c8''
bases.toBase(200, 16) // => ''c8''
bases.toBase62(99999) // => ''q0T''
bases.toBase(200, 62) // => ''q0T''
bases.toAlphabet(300, ''aAbBcC'') // => ''Abba''
bases.fromBase16(''c8'') // => 200
bases.fromBase(''c8'', 16) // => 200
bases.fromBase62(''q0T'') // => 99999
bases.fromBase(''q0T'', 62) // => 99999
bases.fromAlphabet(''Abba'', ''aAbBcC'') // => 300
consulte https://github.com/kamijoutouma/bases.py#known-basesalphabets para saber qué bases son utilizables
¿Cómo convertiría un 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 todos parecen estar ocupados con la conversión de cadenas. El módulo base64 de Python solo acepta cadenas y convierte un solo dígito en cuatro caracteres. Estaba buscando algo parecido a lo que usan los acortadores de URL.
Aquí está mi solución:
def base62(a):
baseit = (lambda a=a, b=62: (not a) and ''0'' or
baseit(a-a%b, b*62) + ''0123456789abcdefghijklmnopqrstuvwxyz''
''ABCDEFGHIJKLMNOPQRSTUVWXYZ''[a%b%61 or -1*bool(a%b)])
return baseit()
explicación
En cualquier base, cada número es igual a a1+a2*base**2+a3*base**3...
Entonces el objetivo es encontrar todas las a
s.
Para cada N=1,2,3...
el código aísla la aN*base**N
por "modulo" por b
para b=base**(N+1)
que corta todas las a
más que N
, y cortando todas las a
s para que su serie sea menor que N
disminuyendo cada vez que la aN*base**N
actual aN*base**N
la función recursiva.
Base%(base-1)==1
por lo tanto base**p%(base-1)==1
y por lo tanto q*base^p%(base-1)==q
con solo una excepción, cuando q==base-1
que devuelve 0
. Para arreglar ese caso, devuelve 0
. La función comprueba 0
desde el principio.
ventajas
En esta muestra solo hay una multiplicación (en lugar de una división) y algunas operaciones de módulo, que son todas relativamente rápidas.
Aquí hay una manera recurrente e iterativa de hacer eso. El iterativo es un poco más rápido dependiendo del conteo de ejecución.
def base62_encode_r(dec):
s = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ''
return s[dec] if dec < 62 else base62_encode_r(dec / 62) + s[dec % 62]
print base62_encode_r(2347878234)
def base62_encode_i(dec):
s = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ''
ret = ''''
while dec > 0:
ret = s[dec % 62] + ret
dec /= 62
return ret
print base62_encode_i(2347878234)
def base62_decode_r(b62):
s = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ''
if len(b62) == 1:
return s.index(b62)
x = base62_decode_r(b62[:-1]) * 62 + s.index(b62[-1:]) % 62
return x
print base62_decode_r("2yTsnM")
def base62_decode_i(b62):
s = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ''
ret = 0
for i in xrange(len(b62)-1,-1,-1):
ret = ret + s.index(b62[i]) * (62**(len(b62)-i-1))
return ret
print base62_decode_i("2yTsnM")
if __name__ == ''__main__'':
import timeit
print(timeit.timeit(stmt="base62_encode_r(2347878234)", setup="from __main__ import base62_encode_r", number=100000))
print(timeit.timeit(stmt="base62_encode_i(2347878234)", setup="from __main__ import base62_encode_i", number=100000))
print(timeit.timeit(stmt="base62_decode_r(''2yTsnM'')", setup="from __main__ import base62_decode_r", number=100000))
print(timeit.timeit(stmt="base62_decode_i(''2yTsnM'')", setup="from __main__ import base62_decode_i", number=100000))
0.270266867033
0.260915645986
0.344734796766
0.311662500262
El siguiente decodificador funciona con cualquier base razonable, tiene un bucle mucho más ordenado y da un mensaje de error explícito cuando se encuentra con un carácter no válido.
def base_n_decoder(alphabet):
"""Return a decoder for a base-n encoded string
Argument:
- `alphabet`: The alphabet used for encoding
"""
base = len(alphabet)
char_value = dict(((c, v) for v, c in enumerate(alphabet)))
def f(string):
num = 0
try:
for char in string:
num = num * base + char_value[char]
except KeyError:
raise ValueError(''Unexpected character %r'' % char)
return num
return f
if __name__ == "__main__":
func = base_n_decoder(''0123456789abcdef'')
for test in (''0'', ''f'', ''2020'', ''ffff'', ''abqdef''):
print test
print func(test)
Escribí esto hace un tiempo y funcionó bastante bien (negativos y todo incluido)
def code(number,base):
try:
int(number),int(base)
except ValueError:
raise ValueError(''code(number,base): number and base must be in base10'')
else:
number,base = int(number),int(base)
if base < 2:
base = 2
if base > 62:
base = 62
numbers = [0,1,2,3,4,5,6,7,8,9,"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t","u","v","w","x","y",
"z","A","B","C","D","E","F","G","H","I","J","K","L","M","N",
"O","P","Q","R","S","T","U","V","W","X","Y","Z"]
final = ""
loc = 0
if number < 0:
final = "-"
number = abs(number)
while base**loc <= number:
loc = loc + 1
for x in range(loc-1,-1,-1):
for y in range(base-1,-1,-1):
if y*(base**x) <= number:
final = "{}{}".format(final,numbers[y])
number = number - y*(base**x)
break
return final
def decode(number,base):
try:
int(base)
except ValueError:
raise ValueError(''decode(value,base): base must be in base10'')
else:
base = int(base)
number = str(number)
if base < 2:
base = 2
if base > 62:
base = 62
numbers = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f",
"g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
"w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L",
"M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
final = 0
if number.startswith("-"):
neg = True
number = list(number)
del(number[0])
temp = number
number = ""
for x in temp:
number = "{}{}".format(number,x)
else:
neg = False
loc = len(number)-1
number = str(number)
for x in number:
if numbers.index(x) > base:
raise ValueError(''{} is out of base{} range''.format(x,str(base)))
final = final+(numbers.index(x)*(base**loc))
loc = loc - 1
if neg:
return -final
else:
return final
perdón por la duración de todo
Espero que el siguiente fragmento pueda ayudar.
def num2sym(num, sym, join_symbol=''''):
if num == 0:
return sym[0]
if num < 0 or type(num) not in (int, long):
raise ValueError(''num must be positive integer'')
l = len(sym) # target number base
r = []
div = num
while div != 0: # base conversion
div, mod = divmod(div, l)
r.append(sym[mod])
return join_symbol.join([x for x in reversed(r)])
Uso para su caso:
number = 367891
alphabet = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ''
print num2sym(number, alphabet) # will print ''1xHJ''
Obviamente, puede especificar otro alfabeto, que consiste en una cantidad menor o mayor de símbolos, luego convertirá su número a la base de números menores o mayores. Por ejemplo, al proporcionar ''01'' como un alfabeto, la cadena de salida representará el número de entrada como binario.
Puede barajar el alfabeto inicialmente para tener su representación única de los números. Puede ser útil si está haciendo un servicio de acortador de URL.
Lo siento, no puedo ayudarte con una biblioteca aquí. Preferiría usar base64 y agregar caracteres extra a tu elección, si es posible.
Entonces puedes usar el módulo base64.
Si esto es realmente, realmente imposible:
Puede hacerlo usted mismo de esta manera (esto es pseudocódigo):
base62vals = []
myBase = 62
while num > 0:
reminder = num % myBase
num = num / myBase
base62vals.insert(0, reminder)
Me he beneficiado enormemente de las publicaciones de otros aquí. Necesitaba el código python originalmente para un proyecto de Django, pero desde entonces he recurrido a node.js, así que aquí hay una versión de JavaScript del código (la parte de codificación) proporcionada por Baishampayan Ghose.
var ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function base62_encode(n, alpha) {
var num = n || 0;
var alphabet = alpha || ALPHABET;
if (num == 0) return alphabet[0];
var arr = [];
var base = alphabet.length;
while(num) {
rem = num % base;
num = (num - rem)/base;
arr.push(alphabet.substring(rem,rem+1));
}
return arr.reverse().join('''');
}
console.log(base62_encode(2390687438976, "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"));
No hay un módulo estándar para esto, pero he escrito mis propias funciones para lograrlo.
BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encode(num, alphabet=BASE62):
"""Encode a positive number in Base X
Arguments:
- `num`: The number to encode
- `alphabet`: The alphabet to use for encoding
"""
if num == 0:
return alphabet[0]
arr = []
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 encoding
"""
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 darle cualquier alfabeto para usar para codificar y decodificar. Si deja fuera el argumento del alphabet
, obtendrá el alfabeto de 62 caracteres definido en la primera línea de código, y por lo tanto la codificación / decodificación a / desde 62 base.
Espero que esto ayude.
PD: para los acortadores de URL, he descubierto que es mejor dejar fuera unos pocos caracteres confusos como 0Ol1oI, etc. Por lo tanto, uso este alfabeto para mis necesidades de acortamiento de URL: "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
Que te diviertas.
Personalmente, me gusta la solución de Baishampayan, sobre todo por despojar a los personajes confusos.
Para completar y solucionar con un mejor rendimiento, esta publicación muestra una forma de utilizar el módulo base64 de Python.
Probablemente quieras base64, no base62. Hay una versión compatible con URL que flota, por lo que los dos caracteres de relleno adicionales no deberían ser un problema.
El proceso es bastante simple; considere que base64 representa 6 bits y un byte regular representa 8. Asigne un valor de 000000 a 111111 a cada uno de los 64 caracteres elegidos, y coloque los 4 valores para que coincidan con un conjunto de 3 base256 bytes. Repita para cada conjunto de 3 bytes, relleno al final con su elección de carácter de relleno (0 generalmente es útil).
Si busca la mayor eficiencia (como django), querrá algo como lo siguiente. Este código es una combinación de métodos eficientes de Baishampayan Ghose y WoLpH y John Machin.
# Edit this list of characters as desired.
BASE_ALPH = tuple("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
BASE_DICT = dict((c, v) for v, c in enumerate(BASE_ALPH))
BASE_LEN = len(BASE_ALPH)
def base_decode(string):
num = 0
for char in string:
num = num * BASE_LEN + BASE_DICT[char]
return num
def base_encode(num):
if not num:
return BASE_ALPH[0]
encoding = ""
while num:
num, rem = divmod(num, BASE_LEN)
encoding = BASE_ALPH[rem] + encoding
return encoding
Es posible que también desee calcular su diccionario de antemano. (Nota: la codificación con una cadena muestra más eficiencia que con una lista, incluso con números muy largos).
>>> timeit.timeit("for i in xrange(1000000): base.base_decode(base.base_encode(i))", setup="import base", number=1)
2.3302059173583984
Codificó y decodificó 1 millón de números en menos de 2.5 segundos. (2.2Ghz i7-2670QM)
Si todo lo que necesita es generar una identificación corta (ya que menciona los acortadores de URL) en lugar de codificar / decodificar algo, este módulo podría ayudar:
Si usa django framework, puede usar el módulo django.utils.baseconv.
>>> from django.utils import baseconv
>>> baseconv.base62.encode(1234567890)
1LY7VK
Además de base62, baseconv también definió base2 / base16 / base36 / base56 / base64.
Tengo una biblioteca de Python para hacer exactamente eso aquí: http://www.djangosnippets.org/snippets/1431/
Una vez escribí un guión para hacer esto, creo que es bastante elegante :)
import string
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
Ejemplo de uso:
for i in range(100):
print i, base_decode(base_encode(i)), base_encode(i)
BASE_LIST = tuple("23456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz")
BASE_DICT = dict((c, v) for v, c in enumerate(BASE_LIST))
BASE_LEN = len(BASE_LIST)
def nice_decode(str):
num = 0
for char in str[::-1]:
num = num * BASE_LEN + BASE_DICT[char]
return num
def nice_encode(num):
if not num:
return BASE_LIST[0]
encoding = ""
while num:
num, rem = divmod(num, BASE_LEN)
encoding += BASE_LIST[rem]
return encoding