[python] 기본 62 변환

정수를 기본 62로 변환하는 방법 (16 진수와 같지만 다음 숫자 : ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’).

나는 그것을 위해 좋은 파이썬 라이브러리를 찾으려고 노력해 왔지만 모두 문자열 변환으로 가득 찬 것처럼 보입니다. Python base64 모듈은 문자열 만 받아들이고 한 자리를 4 자로 바꿉니다. URL 단축기가 사용하는 것과 유사한 것을 찾고있었습니다.



답변

이에 대한 표준 모듈은 없지만이를 달성하기 위해 자체 함수를 작성했습니다.

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

인코딩 및 디코딩에 사용할 알파벳을 지정할 수 있습니다. 당신이 떠날 경우 alphabet인수를, 당신은 코드의 첫 번째 줄에 정의 된 62 문자 알파벳을 얻기 위하여려고하고있다, 따라서 62 기지에서 /로 디코딩 / 인코딩.

도움이 되었기를 바랍니다.

추신-URL 단축기의 경우 0Ol1oI 등과 같은 몇 가지 혼란스러운 문자를 생략하는 것이 더 낫다는 것을 알았습니다. 따라서 URL 단축 요구에이 알파벳을 사용합니다. "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

즐기세요.


답변

한 번도이 작업을 수행하는 스크립트를 작성했는데 꽤 우아하다고 생각합니다. 🙂

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

사용 예 :

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


답변

다음 디코더 제작자는 합리적인 기준으로 작업하고 훨씬 깔끔한 루프를 가지고 있으며 잘못된 문자를 만나면 명시적인 오류 메시지를 제공합니다.

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)


답변

가장 높은 효율성 (예 : django)을 찾고 있다면 다음과 같은 것을 원할 것입니다. 이 코드는 Baishampayan Ghose와 WoLpH 및 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

사전에 사전을 계산할 수도 있습니다. (참고 : 문자열을 사용한 인코딩은 매우 긴 숫자를 사용하더라도 목록보다 더 효율적입니다.)

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

2.5 초 이내에 백만 개의 숫자를 인코딩 및 디코딩했습니다. (2.2Ghz i7-2670QM)


답변

무언가를 인코딩 / 디코딩하는 대신 짧은 ID (URL 단축기를 언급했기 때문에)를 생성하기 만하면이 모듈이 도움이 될 수 있습니다.

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


답변

django 프레임 워크를 사용하는 경우 django.utils.baseconv 모듈을 사용할 수 있습니다.

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

base62 외에도 baseconv는 base2 / base16 / base36 / base56 / base64도 정의했습니다.


답변

아마도 base62가 아닌 base64를 원할 것입니다. URL 호환 버전이 떠 다니므로 추가로 두 개의 필러 문자가 문제가되지 않습니다.

과정은 매우 간단합니다. base64는 6 비트를 나타내고 일반 바이트는 8을 나타냅니다. 선택한 64 자 각각에 000000에서 111111 사이의 값을 할당하고 3 개의 base256 바이트 세트와 일치하도록 4 개의 값을 합칩니다. 3 바이트의 각 세트에 대해 반복하고 마지막에 선택한 패딩 문자로 패딩합니다 (일반적으로 0이 유용함).