Chuyển đổi cơ sở 62


90

Làm cách nào bạn chuyển đổi một số nguyên sang cơ số 62 (như hệ thập lục phân, nhưng với các chữ số sau: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

Tôi đã cố gắng tìm một thư viện Python tốt cho nó, nhưng dường như tất cả chúng đều bận rộn với việc chuyển đổi các chuỗi. Mô-đun base64 của Python chỉ chấp nhận các chuỗi và biến một chữ số duy nhất thành bốn ký tự. Tôi đang tìm kiếm thứ gì đó tương tự như những gì trình rút ngắn URL sử dụng.


Âm thanh như ai đó vừa tìm thấy một ý tưởng dự án mã nguồn mở :) Hãy cho tôi biết nếu bạn tìm thấy bất cứ điều gì hoặc quyết định tạo riêng của bạn ...
samoz

Nếu bạn muốn tạo URL ngắn, bạn có thể muốn sử dụng toàn bộ bộ ký tự không cần mã hóa: en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters . Đó là 66 ký tự.
l0b0

Tôi nghĩ rằng tôi sẽ chuyển dấu chấm và dấu ngã, chỉ để tránh nhầm lẫn cho người dùng, nhưng dấu gạch ngang và dấu gạch dưới sẽ là những bổ sung đáng giá, cảm ơn.
mikl 13/07/09

còn Base64 thì sao? Bạn có thể gặp may mắn hơn khi tìm thấy các thư viện cho điều đó.
Mike Cooper

Câu hỏi này có một số câu trả lời có thể áp dụng: stackoverflow.com/questions/561486/…
Miles

Câu trả lời:


166

Không có mô-đun tiêu chuẩn nào cho việc này, nhưng tôi đã viết các chức năng của riêng mình để đạt được điều đó.

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

Lưu ý thực tế là bạn có thể cung cấp cho nó bất kỳ bảng chữ cái nào để sử dụng để mã hóa và giải mã. Nếu bạn bỏ qua alphabetđối số, bạn sẽ nhận được bảng chữ cái 62 ký tự được xác định trên dòng mã đầu tiên và do đó mã hóa / giải mã thành / từ cơ sở 62.

Hi vọng điêu nay co ich.

Tái bút - Đối với trình rút ngắn URL, tôi nhận thấy rằng tốt hơn nên bỏ đi một vài ký tự khó hiểu như 0Ol1oI, v.v. Vì vậy, tôi sử dụng bảng chữ cái này cho nhu cầu rút ngắn URL của mình - "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

Chúc vui vẻ.


5
+1: Tốt! Điều này có thể được mở rộng với nhiều ký tự thân thiện với URL hơn để có thể lưu một ký tự ở đây và ở đó. Nhân vật mà tôi biết là an toàn là: $-_.+!*'(),;/?:@&= Có thể bạn có thể sử dụng một số nhân vật khác nữa như []~, vv
Blixt

24
Lỗi đặt tên: nó không phải là cơ số 62, vì bảng chữ cái có thể tùy chỉnh.
thư giãn

3
Đối với giải mã, thói quen tốt hơn là không tính lũy thừa (tiết kiệm thời gian, viết ngắn hơn, nhưng quan trọng hơn là tránh được các lỗi riêng lẻ), do đó: num = 0; cho char trong chuỗi: num = num * cơ sở + alphabet.index (char)
ShreevatsaR

1
@ShreevatsaR: bất kỳ lý do cụ thể nào để sử dụng str.index () thay vì tra cứu từ điển? Xem câu trả lời của tôi ...
John Machin

2
Jonathan - Python có thể xử lý số chiều dài tùy ý - không có tràn: >>> 256 * (62 ** 100) 44402652562862911414971048359760030835982580330786570771137804709455598239929932673552190201125730101070867075377228748911717860448985185350731601887476350502973424822800696272224256L
Anthony Briggs

53

Tôi đã từng viết một kịch bản để làm điều này, tôi nghĩ nó khá thanh lịch :)

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

Ví dụ sử dụng:

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

9
Phiên bản này nhanh hơn đáng kể so với giải pháp được chấp nhận từ Baishampayan. Tôi đã tối ưu hóa thêm bằng cách tính toán chiều dài bên ngoài hàm. Kết quả kiểm tra (100.000 lần lặp): version-WoLpH: .403 .399 .399 .398 .398 | phiên bản-Baishampayan: 1.783 1.785 1.782 1.788 1.784. Phiên bản này nhanh hơn khoảng 4x.
Jordan

nếu sử dụng reversed(string)nhanh hơn việc cắt string[::-1]trong hàm base_decode.
ENDOH takanao

1
Tôi đã mất một thời gian dài để tìm câu hỏi này. Không bao giờ biết điều này được gọi là chuyển đổi base62. Câu trả lời hay đấy.

Tôi đã phải thay đổi integer /= lengthđể integer //=lengthcó được phần còn lại chính xác
karlgold

10

Trình tạo bộ giải mã sau hoạt động với bất kỳ cơ sở hợp lý nào, có vòng lặp gọn gàng hơn nhiều và đưa ra thông báo lỗi rõ ràng khi nó gặp ký tự không hợp lệ.

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)

Mặc dù tôi có thể sẽ không bao giờ sử dụng cái này, nhưng tôi cũng đã ủng hộ bạn cho sự sáng tạo. Mã này đã mang lại cho tôi một tiếng cười. :)
Sepero

@Sepero: Có gì vui vậy? Đó là phần mềm công nghiệp mạnh mẽ nghiêm túc. Không có Micky-Mouse đảo ngược với một **toán tử trong vòng lặp.
John Machin

Bình tĩnh đi bạn. Bạn đúng. Tôi đã bỏ lỡ sự tốt đẹp thực sự của vòng lặp bên trong của bạn do nó bị chôn vùi trong những thứ không liên quan đến câu hỏi (gói, kiểm tra lỗi, thử nghiệm đơn vị).
Sepero

Có vẻ tốt, nhưng bạn có quên một bộ mã hóa "công nghiệp mạnh" lấy một số nguyên cộng với bảng chữ cái để tạo ra một chuỗi không?
martineau

1
Có phải q trong giá trị cuối cùng cố ý thể hiện ValueError đang được tăng lên không?
Thomas Vander Stichele

7

Nếu bạn đang tìm kiếm hiệu quả cao nhất (như django), bạn sẽ muốn những thứ như sau. Mã này là sự kết hợp của các phương pháp hiệu quả từ Baishampayan Ghose, WoLpH và 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

Bạn cũng có thể muốn tính toán trước từ điển của mình. (Lưu ý: Mã hóa bằng một chuỗi cho thấy hiệu quả hơn với một danh sách, ngay cả với các số rất dài.)

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

Mã hóa và giải mã 1 triệu số trong thời gian dưới 2,5 giây. (2.2Ghz i7-2670QM)


Một người không nhất thiết cần tuple()xung quanh BASE_ALPHngay từ đầu. Trong Python, mọi chuỗi đều có thể lặp lại. Tính năng đó tất nhiên được khai thác bởi enumerate(). Vì vậy, mã thậm chí còn gọn gàng hơn :)
Luis Nell

6
Xin chào origiNell, bạn nói đúng rằng tuple () không cần thiết, nhưng trên hệ thống của tôi, nó giúp mã chạy nhanh hơn khoảng 20%. Hãy thử kiểm tra nó mà không có tuple () và xem điều gì phù hợp nhất với bạn. Chúc mừng :)
Sepero

Điểm thú vị. Có ý nghĩa hoàn toàn vì bộ giá trị nhẹ hơn bộ dây. Cảm ơn vì đã khai sáng :)!
Luis Nell

@Sepero tôi thêm phiên bản cải tiến của bạn về định dạng, đặt tên, kiểm tra và chức năng (số âm được hỗ trợ): pastebin.com/4uket7iu (bạn có thể cập nhật câu trả lời của bạn với điều này)
Joschua

@Joschua - Mã của bạn tại URL của bạn không phù hợp với tôi. base_encode () dường như chỉ tạo ra một chữ số được mã hóa cho các số tôi đã thử nghiệm.
SMGreenfield

4

Nếu bạn sử dụng khung công tác django, bạn có thể sử dụng mô-đun django.utils.baseconv.

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

Ngoài base62, baseconv cũng định nghĩa base2 / base16 / base36 / base56 / base64.


3

Bạn có thể muốn base64, không base62. Có một phiên bản tương thích với URL của nó nổi xung quanh, vì vậy hai ký tự điền thêm không phải là vấn đề.

Quá trình này khá đơn giản; coi rằng base64 đại diện cho 6 bit và một byte thông thường đại diện cho 8. Gán một giá trị từ 000000 đến 111111 cho từng ký tự trong số 64 ký tự đã chọn và đặt 4 giá trị lại với nhau để khớp với bộ 3 base256 byte. Lặp lại cho mỗi bộ 3 byte, đệm ở cuối với sự lựa chọn của ký tự đệm (0 thường hữu ích).


5
Các phương pháp mã hóa Python base64 tiêu chuẩn không thực sự phù hợp với URL ngắn, vì nó được tối ưu hóa để mã hóa byte (ví dụ: chuỗi / chữ cái) và sẽ tạo ra kết quả đầu ra dài hơn so với chỉ dịch chuyển cơ sở giá trị số.
mikl

@mikl Tất nhiên, mô-đun base64 của Python có thể không phù hợp để tạo URL ngắn, nhưng tất cả các phương pháp mã hóa của Python đều thực sự hoạt động trên chuỗi số cơ sở 256. byte thực sự là "chuỗi" được mã hóa cơ sở 256. Python 2.x xử lý các chuỗi như một chuỗi các byte, trong khi Python 3.x (làm đúng) xử lý các chuỗi là Unicode. Vì vậy, b'foobar 'thực sự chỉ là một cách viết ưa thích [102, 111, 111, 98, 97, 114] hoặc [0x66,0x6f, 0x6f, 0x62,0x61,0x72] hoặc b' \ x66 \ x6f \ x6f \ x62 \ x61 \ x72 'mà không có gì đáng ngạc nhiên là biểu diễn cơ sở 256. Byte không phải là chuỗi hoặc chữ cái. Byte là các byte. =)
yesudeep

@yesudeep: Vì vậy, byte là byte… và chính xác thì quan điểm của bạn là gì?
martineau

3

Nếu tất cả những gì bạn cần là tạo một ID ngắn (vì bạn đề cập đến trình rút gọn URL) thay vì mã hóa / giải mã thứ gì đó, thì mô-đun này có thể giúp:

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


Tôi không chắc điều đó có phù hợp với URL ngắn. Một UUID thường là một số rất lớn, vì vậy ngay cả khi mã hóa base57 nó như anh ta làm thì cũng phải khá dài đối với một URL ngắn.
mikl

Bạn có thể cắt bao nhiêu tùy thích, va chạm sẽ vẫn khó xảy ra vì nó hoàn toàn là ngẫu nhiên, nhưng sẽ không còn là một id duy nhất nữa.
Stavros Korokithakis

2

bạn có thể tải xuống mô-đun zbase62 từ pypi

ví dụ

>>> import zbase62
>>> zbase62.b2a("abcd")
'1mZPsa'

2
Yeah, tôi nhìn mà trước đó, nhưng nó chuyển đổi chuỗi, không phải là số :)
mikl

2

Tôi đã được hưởng lợi rất nhiều từ những bài viết của người khác ở đây. Ban đầu tôi cần mã python cho dự án Django, nhưng kể từ đó tôi đã chuyển sang node.js, vì vậy đây là phiên bảnjavascript (phần mã hóa) mà Baishampayan Ghose đã cung cấp.

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

Tôi đã cập nhật mã này và biến nó thành một dự án nguồn mở cho bất kỳ ai quan tâm github.com/sbussard/encode-the-things
Stephen

2

Tôi hy vọng đoạn mã sau đây có thể giúp ích.

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

Cách sử dụng cho trường hợp của bạn:

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

Rõ ràng, bạn có thể chỉ định một bảng chữ cái khác, bao gồm số lượng ký hiệu ít hơn hoặc lớn hơn, sau đó nó sẽ chuyển đổi số của bạn thành cơ số nhỏ hơn hoặc lớn hơn. Ví dụ: cung cấp '01' dưới dạng bảng chữ cái sẽ xuất ra chuỗi đại diện cho số đầu vào dưới dạng nhị phân.

Ban đầu, bạn có thể xáo trộn bảng chữ cái để có cách biểu diễn các con số duy nhất. Nó có thể hữu ích nếu bạn đang sử dụng dịch vụ rút ngắn URL.


1
Không tệ. Bạn có thể muốn sử dụng if num < 0 or type(num) not in (int, long):.
martineau

Điều đó tốt hơn, nhưng nó phức tạp hơn một chút vì longkhông tồn tại trong Py 3.x - vì vậy người ta có thể muốn sử dụng câu trả lời này .
martineau

1
Hoặc sử dụng phiên bản di động của riêng tôi: isinstance(x, (type(1), type(2**32))).
martineau

2

Hiện có một thư viện python cho việc này.

Tôi đang làm việc để tạo một gói pip cho việc này.

Tôi khuyên bạn nên sử dụng base.py https://github.com/kamijoutouma/bases.py được lấy cảm hứng từ base.js của tôi

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

tham khảo https://github.com/kamijoutouma/bases.py#known-basesalphabets để biết những cơ sở nào có thể sử dụng được


2

Đây là giải pháp của tôi:

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

giải trình

Trong bất kỳ cơ số nào, mọi số đều bằng a1+a2*base**2+a3*base**3...Vì vậy mục tiêu là tìm tất cả các as.

Đối với mỗi N=1,2,3...mã phân lập các aN*base**Nbằng "moduloing" bởi bb=base**(N+1)đó lát tất cả alà lớn hơn N, và cắt tất cả các as để nối tiếp của họ là nhỏ hơn Nbằng cách giảm amọi chức năng được gọi là đệ quy bằng dòng điện aN*base**N.

Base%(base-1)==1do đó base**p%(base-1)==1và do đó q*base^p%(base-1)==qchỉ với một ngoại lệ, khi q==base-1nào trả về 0. Để khắc phục trường hợp đó nó trả về 0. Chức năng kiểm tra 0ngay từ đầu.


lợi thế

Trong mẫu này chỉ có một phép nhân (thay vì phép chia) và một số phép toán mô đun, tất cả đều tương đối nhanh.


1

Cá nhân tôi thích giải pháp từ Baishampayan, chủ yếu là vì loại bỏ các ký tự khó hiểu.

Để có tính hoàn chỉnh và giải pháp có hiệu suất tốt hơn, bài đăng này chỉ ra cách sử dụng mô-đun Python base64.


1
Như đã đề cập trong nhận xét của tôi với Williham Totland, Pythons base64 là không tối ưu để mã hóa số, vì nó được tối ưu hóa cho chuỗi.
mikl

1

Tôi đã viết bài này một thời gian và nó hoạt động khá tốt (âm bản và tất cả được bao gồm)

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

xin lỗi về độ dài của tất cả


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
Điều này sửa tên của BASE_LIST và cũng đảo ngược chuỗi giải mã đã bị bỏ qua trong câu trả lời xuất sắc khác của Spero
paulkav1

1

Đây là một cách khôi phục và lặp lại để làm điều đó. Quá trình lặp lại nhanh hơn một chút tùy thuộc vào số lần thực thi.

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

Tôi thực sự thích cách tiếp cận đệ quy của bạn. Con gái tôi, người đang thi AP Comp Sci, đã tìm ra giải pháp tương tự cho tôi để triển khai "base25" (sử dụng 'ABCDEFHJKMNPQRTUVWXY34789') trong C ++. Tôi đã chuyển đổi nó sang Python và trở thành một người mới hoàn toàn với ngôn ngữ đó đã gặp phải một số trở ngại - điều mà bạn đã giải quyết một cách dễ dàng trong một dòng mã! Bạn thậm chí còn tránh được một vấn đề phổ biến với 0 dịch sang một chuỗi trống trong bảng chữ cái không bắt đầu bằng 0-9. Công việc tuyệt vời! (Tôi không cần số âm, nhưng cách tiếp cận của bạn rất tốt, có thể rất tốt nếu thêm nó cho các trình duyệt trong tương lai)
SMGreenfield

1

Python 3.7.x

Tôi đã tìm thấy github của tiến sĩ cho một số thuật toán khi tìm kiếm tập lệnh base62 hiện có . Nó không hoạt động với phiên bản tối đa hiện tại của Python 3 tại thời điểm này vì vậy tôi đã tiếp tục và sửa khi cần thiết và thực hiện một chút cấu trúc lại. Tôi không thường làm việc với Python và luôn sử dụng nó một cách đặc biệt nên YMMV. Tất cả tín dụng thuộc về Tiến sĩ Zhihua Lai . Tôi vừa mới làm việc với phiên bản Python này.

tập tin 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

tập tin 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])}')

đầu ra của try_base62.py

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

Vì không có thông tin cấp phép trong repo, tôi đã gửi một bài PR để tác giả gốc ít nhất cũng biết những người khác đang sử dụng và sửa đổi mã của họ.


0

Xin lỗi, tôi không thể giúp bạn với thư viện ở đây. Tôi thích sử dụng base64 hơn và chỉ cần thêm các ký tự bổ sung vào lựa chọn của bạn - nếu có thể!

Sau đó, bạn có thể sử dụng mô-đun base64.

Nếu điều này thực sự, thực sự không thể:

Bạn có thể tự làm theo cách này (đây là mã giả):

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

0

với đệ quy đơn giản

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

Đơn giản nhất từ ​​trước đến nay.

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"))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.