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.
Jawaban:
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
alphabet
argumennya, 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.
sumber
$-_.+!*'(),;/?:@&=
Anda mungkin dapat menggunakan beberapa karakter lain juga seperti[]~
dll.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)
sumber
reversed(string)
lebih cepat daripada mengirisstring[::-1]
dalam fungsi base_decode.integer /= length
keinteger //=length
untuk mendapatkan sisa yang benarPembuat 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)
sumber
**
operator di loop.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)
sumber
tuple()
sekitarBASE_ALPH
pada awalnya. Dalam Python, setiap String dapat diulang. Fitur itu tentu saja dimanfaatkan olehenumerate()
. Jadi kodenya menjadi lebih ramping :)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/
sumber
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.
sumber
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).
sumber
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
sumber
Anda dapat mendownload modul zbase62 dari pypi
misalnya
>>> import zbase62 >>> zbase62.b2a("abcd") '1mZPsa'
sumber
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"));
sumber
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.
sumber
if num < 0 or type(num) not in (int, long):
.long
tidak ada di Py 3.x - jadi orang mungkin ingin menggunakan jawaban ini .isinstance(x, (type(1), type(2**32)))
.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 mengisolasiaN*base**N
oleh "moduloing" olehb
untukb=base**(N+1)
yang irisan semuaa
s lebih besar dariN
, dan mengiris semuaa
s sehingga serial mereka lebih kecil dariN
dengan mengurangia
setiap kali fungsi ini dipanggil secara rekursif oleh arusaN*base**N
.Base%(base-1)==1
oleh karena itubase**p%(base-1)==1
dan oleh karena ituq*base^p%(base-1)==q
dengan hanya satu pengecualian, kapanq==base-1
yang kembali0
. Untuk memperbaiki kasus itu, ia kembali0
. Fungsi tersebut memeriksa0
dari awal.keuntungan
Dalam contoh ini hanya ada satu perkalian (bukan pembagian) dan beberapa operasi modulus, yang semuanya relatif cepat.
sumber
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.
sumber
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
sumber
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
sumber
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
sumber
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
Karena tidak ada info lisensi di repo, saya mengirimkan PR sehingga penulis asli setidaknya tahu orang lain menggunakan dan memodifikasi kode mereka.
sumber
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)
sumber
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)
sumber
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"))
sumber