Konversi basis 62

92

Bagaimana Anda mengonversi bilangan bulat menjadi basis 62 (seperti heksadesimal, tetapi dengan digit ini: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

Saya telah mencoba menemukan pustaka Python yang bagus untuk itu, tetapi mereka semua tampaknya sibuk dengan mengonversi string. Modul Python base64 hanya menerima string dan mengubah satu digit menjadi empat karakter. Saya mencari sesuatu yang mirip dengan penyingkat URL yang digunakan.

mikl
sumber
Sepertinya seseorang baru saja menemukan ide proyek open source :) Beri tahu saya jika Anda menemukan sesuatu atau memutuskan untuk membuatnya sendiri ...
samoz
Jika Anda ingin membuat URL singkat, Anda mungkin ingin menggunakan seluruh rangkaian karakter yang tidak perlu dienkode: en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters . Itu 66 karakter.
l0b0
Saya pikir saya akan meneruskan titik dan tilde, hanya untuk menghindari kebingungan pengguna, tetapi tanda hubung dan garis bawah harus menjadi tambahan yang bermanfaat, terima kasih.
mikl
bagaimana dengan Base64? Anda mungkin lebih beruntung menemukan perpustakaan untuk itu.
Mike Cooper
Pertanyaan ini memiliki sejumlah jawaban yang dapat diterapkan: stackoverflow.com/questions/561486/…
Miles

Jawaban:

169

Tidak ada modul standar untuk ini, tetapi saya telah menulis fungsi saya sendiri untuk mencapai itu.

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

Perhatikan fakta bahwa Anda dapat memberikan alfabet apa pun yang akan digunakan untuk encoding dan decoding. Jika Anda membiarkan alphabetargumennya, Anda akan mendapatkan 62 karakter alfabet yang ditentukan pada baris pertama kode, dan karenanya encoding / decoding ke / dari 62 base.

Semoga ini membantu.

PS - Untuk penyingkat URL, saya telah menemukan bahwa lebih baik meninggalkan beberapa karakter yang membingungkan seperti 0Ol1oI dll. Jadi saya menggunakan alfabet ini untuk kebutuhan pemendekan URL saya - "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

Selamat bersenang-senang.

Baishampayan Ghose
sumber
5
+1: Bagus! Ini dapat diperpanjang dengan lebih banyak karakter yang ramah URL untuk kemungkinan menyimpan satu karakter di sana-sini. Karakter yang saya tahu aman adalah: $-_.+!*'(),;/?:@&= Anda mungkin dapat menggunakan beberapa karakter lain juga seperti []~dll.
Blixt
24
Bug penamaan: ini bukan basis 62, karena alfabet dapat disesuaikan.
bersantai
3
Untuk decode, adalah kebiasaan yang lebih baik untuk tidak menghitung pangkat (menghemat waktu, lebih singkat untuk menulis, tetapi yang lebih penting menghindari kesalahan off-by-one), jadi: num = 0; untuk char dalam string: num = num * base + alphabet.index (char)
ShreevatsaR
1
@ ShreevatsaR: ada alasan khusus untuk menggunakan str.index () daripada pencarian kamus? Lihat jawaban saya ...
John Machin
2
Jonathan - Python dapat menangani nomor panjang sewenang-wenang - tidak ada overflow: >>> 256 * (62 ** 100) 44402652562862911414971048359760030835982580330786570771137804709455598239929932673552190201125730101070867075377228748911717860448985185350731601887476350502973424822800696272224256L
Anthony Briggs
53

Saya pernah menulis skrip untuk melakukan ini juga, saya pikir itu cukup elegan :)

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

Contoh penggunaan:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)
Wolph
sumber
9
Versi ini jauh lebih cepat daripada solusi yang diterima dari Baishampayan. Saya mengoptimalkan lebih jauh dengan menghitung panjang di luar fungsi. Hasil pengujian (100.000 iterasi): versi-WoLpH: .403 .399 .399 .398 .398 | versi-Baishampayan: 1.783 1.785 1.782 1.788 1.784. Versi ini kira-kira 4x lebih cepat.
Yordania
jika digunakan reversed(string)lebih cepat daripada mengiris string[::-1]dalam fungsi base_decode.
ENDOH takanao
1
Butuh waktu lama bagi saya untuk menemukan pertanyaan ini. Tidak pernah tahu ini disebut konversi base62. Jawaban bagus.
1
Saya harus pindah integer /= lengthke integer //=lengthuntuk mendapatkan sisa yang benar
karlgold
10

Pembuat dekoder berikut bekerja dengan basis yang masuk akal, memiliki loop yang jauh lebih rapi, dan memberikan pesan kesalahan eksplisit ketika bertemu dengan karakter yang tidak valid.

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
sumber
Meskipun saya mungkin tidak akan pernah menggunakan ini, saya terlalu mengacungkan jempol untuk kreativitas. Kode ini membuatku tertawa. :)
Sepero
@ Sepero: Apa yang lucu? Ini adalah perangkat lunak kekuatan industri yang kuat dan serius. Tidak ada Micky-Mouse yang membalik dengan **operator di loop.
John Machin
Tenangkan dirimu kawan. Kamu benar. Saya merindukan kebaikan sejati dari lingkaran batin Anda karena itu terkubur dalam hal-hal yang tidak terkait dengan pertanyaan (pembungkus, pemeriksaan kesalahan, pengujian unit).
Sepero
Kelihatannya bagus, tetapi apakah Anda tidak melupakan pembuat enkode "kekuatan industri" yang menggunakan bilangan bulat ditambah alfabet untuk menghasilkan string?
martineau
1
Apakah q di nilai terakhir sengaja untuk menunjukkan ValueError yang dimunculkan?
Thomas Vander Stichele
8

Jika Anda mencari efisiensi tertinggi (seperti django), Anda akan menginginkan sesuatu seperti berikut ini. Kode ini merupakan kombinasi metode efisien dari Baishampayan Ghose dan WoLpH dan 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

Anda mungkin juga ingin menghitung kamus Anda sebelumnya. (Catatan: Pengkodean dengan string menunjukkan efisiensi lebih daripada dengan daftar, bahkan dengan angka yang sangat panjang.)

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

Menyandikan dan mendekode 1 juta angka dalam waktu kurang dari 2,5 detik. (2.2Ghz i7-2670QM)

Sepero
sumber
Seseorang tidak selalu membutuhkan tuple()sekitar BASE_ALPHpada awalnya. Dalam Python, setiap String dapat diulang. Fitur itu tentu saja dimanfaatkan oleh enumerate(). Jadi kodenya menjadi lebih ramping :)
Luis Nell
7
Hei origiNell, Anda benar bahwa tuple () tidak diperlukan, tetapi di sistem saya, ini membuat kode berjalan sekitar 20% lebih cepat. Cobalah mengujinya tanpa tupel () dan lihat mana yang terbaik untuk Anda. Cheers :)
Sepero
1
Hal yang menarik. Sangat masuk akal karena tupel lebih ringan daripada string. Terima kasih atas pencerahannya :)!
Luis Nell
@Sepero Saya lebih meningkatkan versi Anda dalam hal pemformatan, penamaan, tes dan fungsionalitas (angka negatif didukung): pastebin.com/4uket7iu (Anda dapat memperbarui jawaban Anda dengan ini)
Joschua
@Joschua - Kode Anda di URL Anda tidak berfungsi untuk saya. base_encode () tampaknya hanya menghasilkan satu digit yang dikodekan untuk nomor yang saya uji.
SMGreenfield
4

Jika yang Anda butuhkan hanyalah menghasilkan ID pendek (karena Anda menyebutkan penyingkat URL) daripada menyandikan / mendekode sesuatu, modul ini mungkin membantu:

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

Stavros Korokithakis
sumber
Saya tidak yakin itu sesuai untuk URL singkat. UUID biasanya berupa angka yang sangat besar, jadi bahkan pengkodean base57 seperti yang dilakukannya akan menjadi agak panjang untuk URL pendek.
mikl
Anda bisa memotong sebanyak yang Anda inginkan, tabrakan masih tidak mungkin karena itu murni acak, tetapi tidak akan menjadi id unik lagi.
Stavros Korokithakis
4

Jika Anda menggunakan kerangka kerja django, Anda dapat menggunakan modul django.utils.baseconv.

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

Selain base62, baseconv juga mendefinisikan base2 / base16 / base36 / base56 / base64.

Ryan Fau
sumber
3

Anda mungkin menginginkan base64, bukan base62. Ada versi yang kompatibel dengan URL yang beredar, jadi dua karakter pengisi tambahan seharusnya tidak menjadi masalah.

Prosesnya cukup sederhana; pertimbangkan bahwa base64 mewakili 6 bit dan byte biasa mewakili 8. Tetapkan nilai dari 000000 hingga 111111 untuk masing-masing 64 karakter yang dipilih, dan gabungkan 4 nilai tersebut untuk mencocokkan satu set 3 base256 byte. Ulangi untuk setiap set 3 byte, padding di bagian akhir dengan karakter padding pilihan Anda (0 umumnya berguna).

Williham Totland
sumber
5
Metode pengkodean standar Python base64 tidak benar-benar cocok untuk URL pendek, karena itu dioptimalkan untuk pengkodean byte (mis. String / huruf), dan akan menghasilkan keluaran yang lebih panjang daripada hanya menggeser basis nilai numerik.
mikl
@mikl Tentu saja, modul base64 Python mungkin tidak cocok untuk membuat URL pendek, tetapi semua metode pengkodean Python benar-benar bekerja pada urutan angka basis 256. byte sebenarnya adalah "string" yang dienkode dengan basis 256. Python 2.x memperlakukan string sebagai urutan byte, sedangkan Python 3.x (yang melakukan hal yang benar) memperlakukan string sebagai Unicode. Jadi b'foobar 'hanyalah sebuah cara penulisan yang mewah [102, 111, 111, 98, 97, 114] atau [0x66,0x6f, 0x6f, 0x62,0x61,0x72] atau b' \ x66 \ x6f \ x6f \ x62 \ x61 \ x72 'yang tidak mengejutkan adalah representasi base-256. Byte bukanlah string atau huruf. Byte adalah byte. =)
yesudeep
@yesudeep: Jadi, byte adalah byte… dan apa sebenarnya maksud Anda?
martineau
3

Sekarang ada pustaka python untuk ini.

Saya sedang membuat paket pip untuk ini.

Saya sarankan Anda menggunakan bases.py saya https://github.com/kamijoutouma/bases.py yang terinspirasi oleh 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

lihat https://github.com/kamijoutouma/bases.py#known-basesalphabets untuk mengetahui basis yang dapat digunakan

Belldandu
sumber
2

Anda dapat mendownload modul zbase62 dari pypi

misalnya

>>> import zbase62
>>> zbase62.b2a("abcd")
'1mZPsa'
anjing hantu74
sumber
2
Ya, saya melihatnya sebelumnya, tetapi itu mengubah string, bukan angka :)
mikl
2

Saya mendapat banyak manfaat dari postingan orang lain di sini. Saya membutuhkan kode python awalnya untuk proyek Django, tetapi sejak itu saya telah beralih ke node.js, jadi inilah versi javascript dari kode (bagian pengkodean) yang disediakan 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"));
Stephen
sumber
Saya telah memperbarui kode ini dan membuatnya menjadi proyek open source untuk siapa saja yang tertarik github.com/sbussard/encode-the-things
Stephen
2

Saya harap cuplikan berikut dapat membantu.

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

Penggunaan untuk kasus Anda:

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

Tentunya, Anda dapat menentukan alfabet lain, yang terdiri dari jumlah simbol yang lebih sedikit atau lebih banyak, kemudian itu akan mengubah nomor Anda menjadi basis bilangan yang lebih kecil atau lebih besar. Misalnya, memberikan '01' sebagai alfabet akan mengeluarkan string yang mewakili nomor masukan sebagai biner.

Anda dapat mengocok alfabet pada awalnya untuk mendapatkan representasi unik dari angka-angka tersebut. Ini dapat membantu jika Anda membuat layanan penyingkat URL.

Vladimir Ignatyev
sumber
1
Tidak buruk. Anda mungkin ingin menggunakan if num < 0 or type(num) not in (int, long):.
martineau
Itu lebih baik, tapi sedikit lebih rumit karena longtidak ada di Py 3.x - jadi orang mungkin ingin menggunakan jawaban ini .
martineau
1
Atau gunakan versi portable saya sendiri: isinstance(x, (type(1), type(2**32))).
martineau
2

Inilah solusi saya:

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

penjelasan

Dalam basis apa pun setiap angka sama dengan a1+a2*base**2+a3*base**3...Jadi tujuannya adalah untuk menemukan semuaa s.

Untuk setiap N=1,2,3...kode mengisolasi aN*base**Noleh "moduloing" oleh buntuk b=base**(N+1)yang irisan semua as lebih besar dari N, dan mengiris semua as sehingga serial mereka lebih kecil dari Ndengan mengurangi asetiap kali fungsi ini dipanggil secara rekursif oleh arus aN*base**N.

Base%(base-1)==1oleh karena itu base**p%(base-1)==1dan oleh karena itu q*base^p%(base-1)==qdengan hanya satu pengecualian, kapan q==base-1yang kembali 0. Untuk memperbaiki kasus itu, ia kembali 0. Fungsi tersebut memeriksa 0dari awal.


keuntungan

Dalam contoh ini hanya ada satu perkalian (bukan pembagian) dan beberapa operasi modulus, yang semuanya relatif cepat.

Shu ba
sumber
1

Secara pribadi saya menyukai solusi dari Baishampayan, terutama karena menghilangkan karakter yang membingungkan.

Untuk kelengkapan, dan solusi dengan kinerja yang lebih baik, posting ini menunjukkan cara menggunakan modul Python base64.

Van Gale
sumber
1
Seperti disebutkan dalam komentar saya untuk Williham Totland, Pythons base64 tidak optimal untuk penyandian angka, karena dioptimalkan untuk string.
mikl
1

Saya menulis ini beberapa waktu yang lalu dan itu bekerja dengan cukup baik (negatif dan semua termasuk)

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

maaf tentang lamanya itu semua

Thropian
sumber
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.dll
sumber
1
Ini memperbaiki nama BASE_LIST dan juga membalikkan string pada decoding yang dihilangkan dalam jawaban Spero yang sebaliknya sangat baik
paulkav1
1

Berikut adalah cara rekurif dan berulang untuk melakukannya. Yang berulang sedikit lebih cepat tergantung pada hitungan eksekusi.

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
sumber
Saya sangat menyukai pendekatan rekursif Anda. Putri saya, yang menggunakan AP Comp Sci, telah menemukan solusi yang sama bagi saya untuk mengimplementasikan "base25" (menggunakan 'ABCDEFHJKMNPQRTUVWXY34789') di C ++. Saya pergi untuk mengubahnya menjadi Python dan menjadi seorang newb total dengan bahasa itu mencapai beberapa batu sandungan - yang Anda selesaikan dengan elegan dalam satu baris kode! Anda bahkan menghindari masalah umum dengan 0 menerjemahkan ke string kosong dalam alfabet yang tidak dimulai dengan 0-9. Kerja bagus! (Saya tidak membutuhkan angka negatif, tetapi pendekatan Anda sangat bagus, mungkin bagus untuk menambahkannya untuk browser masa depan)
SMGreenfield
1

Python 3.7.x

Saya menemukan github PhD untuk beberapa algoritme saat mencari skrip base62 yang ada . Itu tidak berfungsi untuk versi maksimal Python 3 saat ini, jadi saya melanjutkan dan memperbaikinya jika diperlukan dan melakukan sedikit refactoring. Saya biasanya tidak bekerja dengan Python dan selalu menggunakannya ad-hoc jadi YMMV. Semua penghargaan diberikan kepada Dr. Zhihua Lai . Saya baru saja menyelesaikan masalah untuk versi Python ini.

mengajukan 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

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

keluaran dari try_base62.py

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

Karena tidak ada info lisensi di repo, saya mengirimkan PR sehingga penulis asli setidaknya tahu orang lain menggunakan dan memodifikasi kode mereka.

kayleeFrye_onDeck
sumber
0

Maaf, saya tidak bisa membantu Anda dengan perpustakaan di sini. Saya lebih suka menggunakan base64 dan hanya menambahkan karakter tambahan ke pilihan Anda - jika memungkinkan!

Kemudian Anda dapat menggunakan modul base64.

Jika ini benar-benar tidak mungkin:

Anda dapat melakukannya sendiri dengan cara ini (ini adalah pseudo-code):

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

dengan rekursi sederhana

"""
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
sumber
0

Paling sederhana.

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"))
melvil james
sumber