Conversion en base 62

90

Comment convertiriez-vous un entier en base 62 (comme hexadécimal, mais avec ces chiffres: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

J'ai essayé de trouver une bonne bibliothèque Python pour cela, mais elles semblent toutes être occupées à convertir des chaînes. Le module Python base64 n'accepte que les chaînes et transforme un seul chiffre en quatre caractères. Je cherchais quelque chose qui ressemble à ce que les raccourcisseurs d'URL utilisent.

Mikl
la source
On dirait que quelqu'un vient de trouver une idée de projet open source :) Faites-moi savoir si vous trouvez quelque chose ou décidez de créer votre propre ...
samoz
Si vous souhaitez créer des URL courtes, vous pouvez utiliser l'ensemble des caractères qui n'ont pas besoin d'être encodés: en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters . Cela fait 66 caractères.
l0b0
Je pense que je vais passer sur le point et le tilde, juste pour éviter la confusion de l'utilisateur, mais le tiret et les traits de soulignement devraient être des ajouts intéressants, merci.
mikl
qu'en est-il de Base64? Vous aurez peut-être plus de chance de trouver des bibliothèques pour cela.
Mike Cooper du
Cette question a un certain nombre de réponses applicables: stackoverflow.com/questions/561486/…
Miles

Réponses:

166

Il n'y a pas de module standard pour cela, mais j'ai écrit mes propres fonctions pour y parvenir.

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

Notez le fait que vous pouvez lui donner n'importe quel alphabet à utiliser pour l'encodage et le décodage. Si vous laissez l' alphabetargument de côté, vous obtiendrez l'alphabet de 62 caractères défini sur la première ligne de code, et donc l'encodage / décodage vers / à partir de 62 base.

J'espère que cela t'aides.

PS - Pour les raccourcisseurs d'URL, j'ai trouvé qu'il vaut mieux laisser de côté quelques caractères déroutants comme 0Ol1oI etc. Ainsi j'utilise cet alphabet pour mes besoins de raccourcissement d'URL - "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

S'amuser.

Baishampayan Ghose
la source
5
+1: Bien! Cela peut être étendu avec des caractères plus conviviaux pour les URL pour éventuellement enregistrer un caractère ici et là. Les personnages que je sais être sûrs sont: $-_.+!*'(),;/?:@&= Vous pouvez probablement utiliser d'autres caractères comme []~etc.
Blixt
24
Bug de dénomination: ce n'est pas la base 62, puisque l'alphabet est personnalisable.
détendre le
3
Pour le décodage, c'est une meilleure habitude de ne pas calculer les puissances (gagne du temps, est plus court à écrire, mais surtout évite les erreurs off-by-one), donc: num = 0; pour char in string: num = num * base + alphabet.index (char)
ShreevatsaR
1
@ShreevatsaR: une raison particulière d'utiliser str.index () au lieu d'une recherche dans le dictionnaire? Voir ma réponse ...
John Machin
2
Jonathan - Python peut gérer un nombre de longueur arbitraire - il n'y a pas de débordement: >>> 256 * (62 ** 100) 44402652562862911414971048359760030835982580330786570771137804709455598239929932673552190201125730101070867075377228748911717860448985185350731601887476350502973424822800696272224256L
Anthony Briggs
53

Une fois, j'ai écrit un script pour faire cela aussi, je pense que c'est assez élégant :)

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

Exemple d'utilisation:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)
Wolph
la source
9
Cette version est considérablement plus rapide que la solution acceptée de Baishampayan. J'ai encore optimisé en calculant la longueur en dehors de la fonction. Résultats des tests (100 000 itérations): version-WoLpH: .403 .399 .399 .398 .398 | version-Baishampayan: 1.783 1.785 1.782 1.788 1.784. Cette version est environ 4x plus rapide.
Jordanie
si utiliser reversed(string)plus rapidement que le découpage string[::-1]dans la fonction base_decode.
ENDOH takanao
1
Il m'a fallu beaucoup de temps pour trouver cette question. Je n'ai jamais su que cela s'appelait la conversion base62. Bonne réponse.
J'ai dû changer integer /= lengthpour integer //=lengthobtenir le reste correct
karlgold
10

Le décodeur-fabricant suivant fonctionne avec n'importe quelle base raisonnable, a une boucle beaucoup plus ordonnée et donne un message d'erreur explicite lorsqu'il rencontre un caractère invalide.

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)
John Machin
la source
Même si je n'utiliserais probablement jamais cela, je devais aussi vous donner un coup de pouce pour la créativité. Ce code m'a fait rire. :)
Sepero
@Sepero: Qu'est-ce qui est si drôle? C'est un logiciel sérieux et robuste de puissance industrielle. Pas d'inversion de Micky-Mouse avec un **opérateur dans la boucle.
John Machin
Calme-toi ami. Vous avez raison. J'ai raté la vraie bonté de votre boucle intérieure car elle est enfouie dans des éléments sans rapport avec la question (emballage, vérification des erreurs, tests unitaires).
Sepero
Ça a l'air bien, mais n'avez-vous pas oublié un encodeur "de puissance industrielle" qui prend un entier plus un alphabet pour produire une chaîne?
martineau
1
Le q dans la dernière valeur était-il intentionnel pour montrer que ValueError est levé?
Thomas Vander Stichele
7

Si vous recherchez la plus grande efficacité (comme django), vous voudrez quelque chose comme ce qui suit. Ce code est une combinaison de méthodes efficaces de Baishampayan Ghose et WoLpH et 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

Vous pouvez également calculer votre dictionnaire à l'avance. (Remarque: l'encodage avec une chaîne est plus efficace qu'avec une liste, même avec des nombres très longs.)

>>> timeit.timeit("for i in xrange(1000000): base.base_decode(base.base_encode(i))", setup="import base", number=1)
2.3302059173583984

Encodé et décodé 1 million de nombres en moins de 2,5 secondes. (2,2 GHz i7-2670QM)

Sepero
la source
On n'a pas nécessairement besoin de ce tuple()qui se passe BASE_ALPHau début. En Python, chaque chaîne est itérable. Cette fonctionnalité est bien sûr exploitée par enumerate(). Le code devient donc encore plus léger :)
Luis Nell
6
Hey origiNell, vous avez raison de dire que le tuple () n'est pas nécessaire, mais sur mon système, cela rend le code 20% plus rapide. Essayez de le tester sans le tuple () et voyez ce qui fonctionne le mieux pour vous. Cheers :)
Sepero
Point intéressant. Cela a tout son sens puisque les tuples sont plus légers que les chaînes. Merci pour l'illumination :)!
Luis Nell
@Sepero J'ai encore amélioré votre version en termes de formatage, de dénomination, de tests et de fonctionnalités (les nombres négatifs sont pris en charge): pastebin.com/4uket7iu (vous pouvez mettre à jour votre réponse avec ceci)
Joschua
@Joschua - Votre code à votre URL n'a pas fonctionné pour moi. base_encode () semblait ne générer qu'un seul chiffre encodé pour les nombres que j'ai testés.
SMGreenfield
4

Si vous utilisez le framework django, vous pouvez utiliser le module django.utils.baseconv.

>>> from django.utils import baseconv
>>> baseconv.base62.encode(1234567890)
1LY7VK

En plus de base62, baseconv a également défini base2 / base16 / base36 / base56 / base64.

Ryan Fau
la source
3

Vous voulez probablement base64, pas base62. Il existe une version compatible URL de celui-ci flottant, donc les deux caractères de remplissage supplémentaires ne devraient pas poser de problème.

Le processus est assez simple; considérez que base64 représente 6 bits et un octet régulier représente 8. Attribuez une valeur de 000000 à 111111 à chacun des 64 caractères choisis, et mettez les 4 valeurs ensemble pour correspondre à un ensemble de 3 base256 octets. Répétez pour chaque ensemble de 3 octets, en remplissant à la fin votre choix de caractère de remplissage (0 est généralement utile).

Williham Totland
la source
5
Les méthodes de codage Python base64 standard ne sont pas vraiment adaptées aux URL courtes, car elles sont optimisées pour le codage d'octets (c.-à-d. Chaînes / lettres), et produiront des sorties plus longues que le simple décalage de base de la valeur numérique.
mikl
@mikl Bien sûr, le module base64 de Python peut ne pas convenir pour générer des URL courtes, mais toutes les méthodes de codage de Python fonctionnent vraiment sur des séquences de nombres en base 256. les octets sont en réalité des "chaînes" codées en base 256. Python 2.x traite les chaînes comme une séquence d'octets, tandis que Python 3.x (qui fait ce qu'il faut) traite les chaînes comme Unicode. Donc b'foobar 'n'est en réalité qu'une manière sophistiquée d'écrire [102, 111, 111, 98, 97, 114] ou [0x66,0x6f, 0x6f, 0x62,0x61,0x72] ou b' \ x66 \ x6f \ x6f \ x62 \ x61 \ x72 'qui, sans surprise, est la représentation en base 256. Les octets ne sont ni des chaînes ni des lettres. Les octets sont des octets. =)
yesudeep
@yesudeep: Donc, les octets sont des octets… et quel est exactement votre point?
martineau
3

Si tout ce dont vous avez besoin est de générer un identifiant court (puisque vous mentionnez des raccourcisseurs d'URL) plutôt que d'encoder / décoder quelque chose, ce module peut vous aider:

https://github.com/stochastic-technologies/shortuuid/

Stavros Korokithakis
la source
Je ne suis pas sûr que ce soit approprié pour les URL courtes. Un UUID est généralement un très grand nombre, donc même l'encodage base57 comme il le fait est forcément assez long pour une URL courte.
mikl
Vous pouvez simplement couper autant que vous le souhaitez, les collisions seront toujours improbables car elles sont purement aléatoires, mais ne seront plus un identifiant unique.
Stavros Korokithakis
2

vous pouvez télécharger le module zbase62 depuis pypi

par exemple

>>> import zbase62
>>> zbase62.b2a("abcd")
'1mZPsa'
ghostdog74
la source
2
Ouais, j'ai regardé ça plus tôt, mais cela convertit des chaînes, pas des nombres :)
mikl
2

J'ai beaucoup profité des publications des autres ici. J'avais besoin du code python à l'origine pour un projet Django, mais depuis, je me suis tourné vers node.js, voici donc une version javascript du code (la partie encodage) que Baishampayan Ghose a fourni.

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"));
Stephen
la source
J'ai mis à jour ce code et en ai fait un projet open source pour tous ceux qui sont intéressés github.com/sbussard/encode-the-things
Stephen
2

J'espère que l'extrait suivant pourra vous aider.

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)])

Utilisation pour votre cas:

number = 367891
alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
print num2sym(number, alphabet)  # will print '1xHJ'

Évidemment, vous pouvez spécifier un autre alphabet, composé d'un nombre inférieur ou supérieur de symboles, puis il convertira votre nombre en base numérique inférieure ou supérieure. Par exemple, fournir «01» comme alphabet produira une chaîne représentant le nombre d'entrée sous forme de binaire.

Vous pouvez d'abord mélanger l'alphabet pour avoir votre représentation unique des nombres. Cela peut être utile si vous créez un service de raccourcissement d'URL.

Vladimir Ignatyev
la source
1
Pas mal. Vous voudrez peut-être utiliser if num < 0 or type(num) not in (int, long):.
martineau
C'est mieux, mais c'est un peu plus compliqué car il longn'existe pas dans Py 3.x - on pourrait donc vouloir utiliser cette réponse .
martineau
1
Ou utiliser ma propre version portable: isinstance(x, (type(1), type(2**32))).
martineau
2

Il existe maintenant une bibliothèque python pour cela.

Je travaille sur la création d'un package pip pour cela.

Je vous recommande d'utiliser mon bases.py https://github.com/kamijoutouma/bases.py qui a été inspiré par 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

reportez-vous à https://github.com/kamijoutouma/bases.py#known-basesalphabets pour connaître les bases utilisables

Belldandu
la source
2

Voici ma solution:

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()

explication

Dans n'importe quelle base, chaque nombre est égal à a1+a2*base**2+a3*base**3...Donc le but est de trouver tous les as.

Pour tout N=1,2,3...le code isole le aN*base**Nen "modulant" par bpour b=base**(N+1)quelles tranches tous les as plus grands que N, et en découpant tous les as pour que leur série soit plus petite qu'en Ndiminuant à achaque fois que la fonction est appelée récursivement par le courant aN*base**N.

Base%(base-1)==1donc base**p%(base-1)==1et donc q*base^p%(base-1)==qà une seule exception, quand q==base-1qui revient 0. Pour résoudre ce cas, il revient 0. La fonction vérifie 0depuis le début.


avantages

Dans cet exemple, il n'y a qu'une seule multiplication (au lieu d'une division) et quelques opérations de module, qui sont toutes relativement rapides.

Shu ba
la source
1

Personnellement, j'aime la solution de Baishampayan, principalement à cause du décapage des personnages déroutants.

Pour être complet et pour une solution avec de meilleures performances, cet article montre un moyen d'utiliser le module Python base64.

Van Gale
la source
1
Comme mentionné dans mon commentaire à Williham Totland, Pythons base64 est sous-optimal pour l'encodage des nombres, car il est optimisé pour les chaînes.
mikl
1

J'ai écrit ceci il y a quelque temps et ça a plutôt bien fonctionné (négatifs et tout inclus)

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

désolé pour la durée de tout ça

Thropian
la source
1
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
paulkav1
la source
1
Cela corrige le nom de BASE_LIST et inverse également la chaîne de décodage qui a été omise dans l'excellente réponse de
Spero
1

Voici une façon récurrente et itérative de le faire. L'itératif est un peu plus rapide en fonction du nombre d'exécutions.

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
Wenzul
la source
J'ai beaucoup aimé votre approche récursive. Ma fille, qui prenait AP Comp Sci, avait trouvé cette même solution pour moi d'implémenter un "base25" (en utilisant 'ABCDEFHJKMNPQRTUVWXY34789') en C ++. Je suis allé le convertir en Python et être un novice total avec ce langage a heurté quelques pierres d'achoppement - que vous avez élégamment résolues en une seule ligne de code! Vous évitez même un problème courant avec 0 se traduisant par une chaîne vide dans les alphabets qui ne commencent pas par 0-9. Bon travail! (Je n'ai pas besoin de nombres négatifs, mais votre approche était si bonne qu'il serait peut-être bien d'ajouter cela pour les futurs navigateurs)
SMGreenfield
1

Python 3.7.x

J'ai trouvé un github de doctorat pour certains algorithmes lors de la recherche d'un script base62 existant . Cela ne fonctionnait pas pour la version max actuelle de Python 3 à ce moment-là, je suis donc allé de l'avant et j'ai corrigé le cas échéant et fait un peu de refactorisation. Je ne travaille généralement pas avec Python et je l'ai toujours utilisé ad hoc donc YMMV. Tout le mérite revient au Dr Zhihua Lai . Je viens de résoudre les problèmes de cette version de Python.

fichier base62.py

#modified from Dr. Zhihua Lai's original on GitHub
from math import floor
base = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
b = 62;
def toBase10(b62: str) -> int:
    limit = len(b62)
    res = 0
    for i in range(limit):
        res = b * res + base.find(b62[i])
    return res
def toBase62(b10: int) -> str:
    if b <= 0 or b > 62:
        return 0
    r = b10 % b
    res = base[r];
    q = floor(b10 / b)
    while q:
        r = q % b
        q = floor(q / b)
        res = base[int(r)] + res
    return res

fichier try_base62.py

import base62
print("Base10 ==> Base62")
for i in range(999):
    print(f'{i} => {base62.toBase62(i)}')
base62_samples = ["gud", "GA", "mE", "lo", "lz", "OMFGWTFLMFAOENCODING"]
print("Base62 ==> Base10")
for i in range(len(base62_samples)):
    print(f'{base62_samples[i]} => {base62.toBase10(base62_samples[i])}')

sortie de try_base62.py

Base10 ==> Base62
0 => 0
[...]
998 => g6
Base62 ==> Base10
gud => 63377
GA => 2640
mE => 1404
lo => 1326
lz => 1337
OMFGWTFLMFAOENCODING => 577002768656147353068189971419611424

Puisqu'il n'y avait aucune information de licence dans le repo, j'ai soumis un PR afin que l'auteur original sache au moins que d'autres personnes utilisent et modifient leur code.

kayleeFrye_onDeck
la source
0

Désolé, je ne peux pas vous aider avec une bibliothèque ici. Je préférerais utiliser base64 et simplement ajouter des caractères supplémentaires à votre choix - si possible!

Ensuite, vous pouvez utiliser le module base64.

Si ce n'est vraiment, vraiment pas possible:

Vous pouvez le faire vous-même de cette façon (c'est un pseudo-code):

base62vals = []
myBase = 62
while num > 0:
   reminder = num % myBase
   num = num / myBase
   base62vals.insert(0, reminder)
Juergen
la source
0

avec récursion simple

"""
This module contains functions to transform a number to string and vice-versa
"""
BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
LEN_BASE = len(BASE)


def encode(num):
    """
    This function encodes the given number into alpha numeric string
    """

    if num < LEN_BASE:
        return BASE[num]

    return BASE[num % LEN_BASE] + encode(num//LEN_BASE)


def decode_recursive(string, index):
    """
    recursive util function for decode
    """

    if not string or index >= len(string):
        return 0

    return (BASE.index(string[index]) * LEN_BASE ** index) + decode_recursive(string, index + 1)


def decode(string):
    """
    This function decodes given string to number
    """

    return decode_recursive(string, 0)
Lokesh Sanapalli
la source
0

Le plus simple jamais.

BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encode_base62(num):
    s = ""
    while num>0:
      num,r = divmod(num,62)
      s = BASE62[r]+s
    return s


def decode_base62(num):
   x,s = 1,0
   for i in range(len(num)-1,-1,-1):
      s = int(BASE62.index(num[i])) *x + s
      x*=62
   return s

print(encode_base62(123))
print(decode_base62("1Z"))
james melvil
la source