Baz 62 dönüşümü


92

Bir tamsayıyı 62 tabanına nasıl dönüştürebilirsiniz (onaltılık gibi, ancak şu rakamlarla: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

Bunun için iyi bir Python kitaplığı bulmaya çalışıyorum, ancak hepsi dizeleri dönüştürmekle meşgul görünüyor. Python base64 modülü yalnızca dizeleri kabul eder ve tek bir rakamı dört karaktere dönüştürür. URL kısaltıcıların kullandığına benzer bir şey arıyordum.


Görünüşe göre birisi açık kaynaklı bir proje fikri bulmuş gibi :) Bir şey bulursanız veya kendi fikrinizi oluşturmaya karar verirseniz bana bildirin ...
samoz

Kısa URL'ler oluşturmak istiyorsanız, kodlanması gerekmeyen tüm karakter kümesini kullanmak isteyebilirsiniz: en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters . Bu 66 karakter.
l0b0

Sanırım sadece kullanıcının kafa karışıklığını önlemek için nokta ve tilde işaretini geçeceğim, ancak kısa çizgi ve altçizgi değerli eklemeler olmalı, teşekkürler.
mikl

ya Base64? Bunun için kitaplık bulma şansınız daha yüksek olabilir.
Mike Cooper

Bu sorunun bir dizi uygulanabilir cevabı vardır: stackoverflow.com/questions/561486/…
Miles

Yanıtlar:


169

Bunun için standart bir modül yok, ancak bunu başarmak için kendi işlevlerimi yazdım.

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

Kodlama ve kod çözme için kullanmak üzere herhangi bir alfabe verebileceğiniz gerçeğine dikkat edin. Eğer bırakırsanalphabet argümanı dışarıda kodun ilk satırında tanımlanan 62 karakterli alfabeyi elde edersiniz ve dolayısıyla 62 bazdan / bazına kodlama / kod çözme işlemi gerçekleştirirsiniz.

Bu yardımcı olur umarım.

Not - URL kısaltıcılar için, 0Ol1oI gibi birkaç kafa karıştırıcı karakteri dışarıda bırakmanın daha iyi olduğunu buldum. Bu nedenle, URL kısaltma ihtiyaçlarım için bu alfabeyi kullanıyorum - "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

İyi eğlenceler.


5
+1: Güzel! Bu, muhtemelen burada ve burada bir karakter kaydetmek için daha fazla URL dostu karakterle genişletilebilir. Güvenli olduğunu bildiğim karakterler: $-_.+!*'(),;/?:@&= Muhtemelen başka karakterleri de kullanabilirsiniz, []~vb.
Blixt

24
Adlandırma hatası: Alfabe özelleştirilebilir olduğu için temel 62 değil.
gevşeyin

3
Kod çözme için, güçleri hesaplamamak daha iyi bir alışkanlıktır (zaman kazandırır, yazmak daha kısadır, ancak daha da önemlisi tek tek hataları önler), dolayısıyla: num = 0; dizede karakter için: num = num * base + alphabet.index (char)
ShreevatsaR

1
@ShreevatsaR: sözlük araması yerine str.index () kullanmanın belirli bir nedeni var mı? Cevabımı görün ...
John Machin

2
>>> 256 * (62 ** 100) 44402652562862911414971048359760030835982580330786570771137804709455598239929932673552190201125730101070867075377228748911717860448985185350731601887476350502973424822800696272224256L: Jonathan - - Python keyfi uzunlukta numaralarını işleyebilir hiçbir taşma yoktur
Anthony Briggs

53

Bir keresinde bunu yapmak için bir senaryo yazmıştım, oldukça zarif olduğunu düşünüyorum :)

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

Örnek kullanım:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)

9
Bu sürüm, Baishampayan'ın kabul ettiği çözümden çok daha hızlıdır. İşlevin dışındaki uzunluğu hesaplayarak daha da optimize ettim. Test sonuçları (100.000 yineleme): sürüm WoLpH: .403 .399 .399 .398 .398 | Baishampayan sürümü: 1.783 1.785 1.782 1.788 1.784. Bu sürüm yaklaşık 4 kat daha hızlıdır.
Ürdün

base_decode işlevinde reversed(string)dilimlemeden daha hızlı kullanılırsa string[::-1].
ENDOH takanao

1
Bu soruyu bulmam uzun zaman aldı. Bunun base62 dönüşümü olduğunu hiç bilmiyordum. Güzel cevap.

1
Ben değiştirmek zorunda integer /= lengthiçin integer //=lengthdoğru kalanını almak için
karlgold

10

Aşağıdaki kod çözücü-yapıcı herhangi bir makul tabanla çalışır, çok daha düzenli bir döngüye sahiptir ve geçersiz bir karakterle karşılaştığında açık bir hata mesajı verir.

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)

Muhtemelen bunu asla kullanmayacak olsam da, yaratıcılık için sana da bir başparmak vermiştim. Bu kod beni güldürdü. :)
Sepero

@Sepero: Bu kadar komik olan ne? Ciddi, sağlam endüstriyel güçte bir yazılımdır. Döngüde bir **operatör varken Micky-Mouse'un geri gitmesi yok .
John Machin

Kendini sakinleştir dostum. Haklısın. Soruyla ilgisi olmayan şeylerin (sarma, hata kontrolü, birim testi) içine gömülü olduğu için iç döngünüzün gerçek iyiliğini kaçırdım.
2013

İyi görünüyor, ancak bir dizi oluşturmak için bir tam sayı artı alfabe alan "endüstriyel güçte" bir kodlayıcıyı unutmadınız mı?
martineau

1
Son değerdeki q, yükseltilmekte olan ValueError'ı göstermek için kasıtlı mıydı?
Thomas Vander Stichele

8

En yüksek verimliliği (django gibi) arıyorsanız, aşağıdaki gibi bir şey isteyeceksiniz. Bu kod, Baishampayan Ghose ve WoLpH ve John Machin'in verimli yöntemlerinin bir kombinasyonudur.

# 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

Ayrıca sözlüğünüzü önceden hesaplamak isteyebilirsiniz. (Not: Bir dizeyle kodlama, çok uzun sayılarda bile bir listeden daha fazla verimlilik gösterir.)

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

1 milyon sayıyı 2,5 saniyenin altında kodladı ve çözdü. (2,2 Ghz i7-2670QM)


Başlangıçta mutlaka tuple()etrafa ihtiyaç duyulmaz BASE_ALPH. Python'da her String yinelenebilir. Bu özellik elbette tarafından istismar edilmektedir enumerate(). Böylece kod daha da zayıflıyor :)
Luis Nell

7
Hey origiNell, tuple () 'ye ihtiyaç olmadığı konusunda haklısın, ama benim sistemimde kodun yaklaşık% 20 daha hızlı çalışmasını sağlıyor. Tuple () olmadan test etmeyi deneyin ve sizin için en iyi olanı görün. Şerefe :)
Sepero

1
İlginç bir nokta. Tuplelar dizelerden daha hafif olduğu için tamamen mantıklı. Aydınlanma için teşekkürler :)!
Luis Nell

@Sepero Sürümünüzü biçimlendirme, adlandırma, testler ve işlevsellik açısından daha da geliştirdim (negatif sayılar desteklenir): pastebin.com/4uket7iu (bununla cevabınızı güncelleyebilirsiniz)
Joschua

@Joschua - URL'nizdeki kodunuz benim için çalışmadı. base_encode (), test ettiğim sayılar için yalnızca bir kodlanmış basamak oluşturuyor gibiydi.
SMGreenfield

4

İhtiyacınız olan tek şey bir şeyi kodlamak / çözmek yerine kısa bir kimlik oluşturmaksa (URL kısaltıcılardan bahsettiğiniz için), bu modül yardımcı olabilir:

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


Kısa URL'ler için uygun olduğundan emin değilim. Bir UUID genellikle çok büyük bir sayıdır, bu nedenle onu onun yaptığı gibi kodlayan base57 bile kısa bir URL için oldukça uzun olacaktır.
mikl

İstediğiniz kadar kesebilirsiniz, tamamen rastgele olduğu için çarpışmalar yine de olası olmayacak, ancak artık benzersiz bir kimlik olmayacak.
Stavros Korokithakis

4

Django framework kullanıyorsanız django.utils.baseconv modülünü kullanabilirsiniz.

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

Base62'ye ek olarak, baseconv ayrıca base2 / base16 / base36 / base56 / base64'ü tanımladı.


3

Muhtemelen base64 istersiniz, base62'yi değil. Etrafta dolaşan URL uyumlu bir sürümü var, bu nedenle fazladan iki dolgu karakteri sorun olmamalı.

İşlem oldukça basittir; base64'ün 6 biti ve normal baytın 8'i temsil ettiğini düşünün. Seçilen 64 karakterin her birine 000000 ile 111111 arasında bir değer atayın ve 4 değeri 3 base256 baytlık bir kümeyle eşleşecek şekilde bir araya getirin. Her 3 baytlık set için tekrarlayın, sonunda seçtiğiniz dolgu karakteri ile doldurun (0 genellikle yararlıdır).


5
Standart Python base64 kodlama yöntemleri, baytları (yani dizeler / harfler) kodlamak için optimize edildiğinden ve sayısal değerin tabanına kaydırılmasından daha uzun çıktılar üreteceğinden, kısa URL'ler için gerçekten uygun değildir.
mikl

@mikl Tabii ki, Python'un base64 modülü kısa URL'ler oluşturmak için uygun olmayabilir, ancak Python'un tüm kodlama yöntemleri gerçekten 256 tabanlı sayı dizileri üzerinde çalışıyor. baytlar gerçekten temel 256 kodlanmış "dizelerdir". Python 2.x dizeleri bir bayt dizisi olarak ele alırken, Python 3.x (doğru olanı yapar) dizeleri Unicode olarak ele alır. Bu yüzden b'foobar 'gerçekten sadece süslü bir yazma biçimidir [102, 111, 111, 98, 97, 114] veya [0x66,0x6f, 0x6f, 0x62,0x61,0x72] veya b' \ x66 \ x6f \ x6f \ x62 \ x61 \ x72 ', şaşırtıcı olmayan bir şekilde taban 256 gösterimidir. Baytlar dizeler veya harfler değildir. Baytlar bayttır. =)
yesudeep

@yesudeep: Yani, baytlar bayttır… ve tam olarak ne demek istiyorsun?
martineau

3

Artık bunun için bir python kitaplığı var.

Bunun için pip paketi yapmaya çalışıyorum.

Bases.js'den ilham alan bases.py https://github.com/kamijoutouma/bases.py'yi kullanmanızı tavsiye ederim.

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

Hangi bazların kullanılabilir olduğunu öğrenmek için https://github.com/kamijoutouma/bases.py#known-basesalphabets'e bakın



2

Başkalarının buradaki gönderilerinden çok faydalandım. Bir Django projesi için orijinal olarak python koduna ihtiyacım vardı, ancak o zamandan beri node.js'ye döndüm, işte Baishampayan Ghose'un sağladığı kodun (kodlama kısmı) bir javascript sürümü .

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"));

Bu kodu güncelledim ve ilgilenen herkes için github.com/sbussard/encode-the-things
Stephen

2

Umarım aşağıdaki kod parçası yardımcı olabilir.

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

Davanız için kullanım:

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

Açıkçası, daha az veya daha fazla sayıda sembolden oluşan başka bir alfabe belirtebilirsiniz, ardından sayınızı daha az veya daha büyük sayı tabanına dönüştürecektir. Örneğin, bir alfabe olarak '01' sağlanması, giriş numarasını ikili olarak temsil eden dizeyi çıktı olarak verecektir.

Rakamların benzersiz temsiline sahip olmak için başlangıçta alfabeyi karıştırabilirsiniz. URL kısaltıcı hizmeti yapıyorsanız yardımcı olabilir.


1
Fena değil. Kullanmak isteyebilirsin if num < 0 or type(num) not in (int, long):.
martineau

Bu daha iyi, ancak biraz daha karmaşık çünkü longPy 3.x'te yok - bu yüzden bu cevabı kullanmak isteyebilirsiniz .
martineau

1
Ya kendi taşınabilir sürümünü kullanın: isinstance(x, (type(1), type(2**32))).
martineau

2

İşte benim çözümüm:

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

açıklama

Herhangi bir tabanda her sayı eşittir. a1+a2*base**2+a3*base**3...Yani amaç tüm as'leri bulmaktır .

Her N=1,2,3...kod için, hangi dilimlerin tümünün daha büyük olduğu aN*base**N"moduloing" ile izole eder ve tüm e'leri dilimleyerek , işlev akım tarafından yinelemeli olarak her çağrıldığında azaltılmasından daha küçük olacak şekilde dilimlenir .bb=base**(N+1)aNaNaaN*base**N

Base%(base-1)==1bu nedenle base**p%(base-1)==1ve bu nedenle q*base^p%(base-1)==qyalnızca bir istisna ile, q==base-1hangisinin geri döndüğü 0. Bu durumu düzeltmek için geri döner 0. İşlev 0baştan kontrol eder .


avantajları

Bu örnekte, tümü nispeten hızlı olan yalnızca bir çarpma (bölme yerine) ve bazı modüllü işlemler vardır.


1

Şahsen, Baishampayan'ın çözümünü, çoğunlukla kafa karıştırıcı karakterleri sıyırdığı için seviyorum.

Tamlık ve daha iyi performans ile çözüm için, bu gönderi Python base64 modülünü kullanmanın bir yolunu gösterir.


1
Williham Totland'a yaptığım yorumda belirtildiği gibi, Pythons base64, dizeler için optimize edildiği için sayıları kodlamak için yetersizdir.
mikl

1

Bunu bir süre önce yazdım ve oldukça iyi çalıştı (negatifler ve hepsi dahil)

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

her şeyin uzunluğu için üzgünüm


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

1
Bu, BASE_LIST ismini düzeltir ve aynı zamanda Spero'nun başka türlü mükemmel cevabında atlanan kod çözme dizisini tersine çevirir
paulkav1

1

İşte bunu yapmanın tekrarlı ve yinelemeli bir yolu. Yinelemeli, yürütme sayısına bağlı olarak biraz daha hızlıdır.

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

Yinelemeli yaklaşımınızı gerçekten beğendim. AP Comp Sci alan kızım, C ++ 'da bir "base25" (' ABCDEFHJKMNPQRTUVWXY34789 'kullanarak) uygulamak için benim için aynı çözümü bulmuştu. Onu Python'a dönüştürmeye gittim ve bu dille tamamen yeni biri olarak birkaç tökezleyen bloğa çarptım - bunu tek bir kod satırında zarif bir şekilde çözdünüz! 0-9 ile başlamayan alfabelerde 0'ın boş bir dizeye çevrilmesiyle ilgili yaygın bir sorundan bile kaçınıyorsunuz. Harika iş! (Negatif sayılara ihtiyacım yok, ancak yaklaşımınız o kadar iyiydi ki gelecekteki tarayıcılar için bunu eklemek güzel olabilir)
SMGreenfield

1

Python 3.7.x

Mevcut bir base62 komut dosyasını ararken bazı algoritmalar için bir doktora github buldum . Şu anda Python 3'ün şu anki maksimum sürümü için işe yaramadı, bu yüzden ilerledim ve gerektiğinde düzeltildim ve biraz yeniden düzenleme yaptım. Genellikle Python ile çalışmıyorum ve her zaman geçici olarak kullandım, yani YMMV. Tüm kredi Dr. Zhihua Lai'ye gidiyor . Az önce Python'un bu sürümü için karışıklıkları çözdüm.

dosya 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

dosya 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])}')

çıktı try_base62.py

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

Depoda herhangi bir lisans bilgisi olmadığı için bir PR gönderdim, böylece orijinal yazar en azından başkalarının kodlarını kullandığını ve değiştirdiğini biliyor.


0

Maalesef burada bir kitaplık konusunda sana yardımcı olamam. Base64 kullanmayı ve sadece seçiminize fazladan karakter eklemeyi tercih ederim - mümkünse!

Ardından, base64 modülünü kullanabilirsiniz.

Bu gerçekten mümkün değilse:

Bunu kendiniz şu şekilde yapabilirsiniz (bu sözde koddur):

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

0

basit özyineleme ile

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


0

Şimdiye kadarki en basit.

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"))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.