基地62转换

mik*_*ikl 77 python math base62

如何将整数转换为基数62(如十六进制,但使用这些数字:'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ').

我一直在努力为它找到一个好的Python库,但它们似乎都在转换字符串.Python base64模块只接受字符串并将一个数字转换为四个字符.我正在寻找类似于URL缩短器使用的东西.

Bai*_*ose 148

没有标准的模块,但我已经编写了自己的功能来实现这一目标.

BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

def encode(num, alphabet=BASE62):
    """Encode a positive number in Base X

    Arguments:
    - `num`: The number to encode
    - `alphabet`: The alphabet to use for encoding
    """
    if num == 0:
        return alphabet[0]
    arr = []
    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 encoding
    """
    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
Run Code Online (Sandbox Code Playgroud)

请注意,您可以为其提供任何用于编码和解码的字母表.如果你退出alphabet论证,你将获得在第一行代码上定义的62个字符的字母表,从而编码/解码到62个基数.

希望这可以帮助.

PS - 对于URL缩短器,我发现最好省略一些令人困惑的字符,如0Ol1oI等.因此,我使用这个字母表来缩短我的URL缩短需求 - "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

玩得开心.

  • 命名错误:它不是基础62,因为字母表是可自定义的. (20认同)
  • +1:太好了!这可以通过更多URL友好的字符进行扩展,从而可以在这里和那里保存一个字符.我认识的字符是安全的:`$ -_.+!*'(),; /?:@&=`您可以使用其他一些字符,如`[] ~`等. (5认同)
  • 对于解码,更好的习惯是不计算功率(节省时间,写入时间更短,但更重要的是避免逐个错误),因此:num = 0; for string in string:num = num*base + alphabet.index(char) (2认同)
  • 乔纳森 - Python可以处理任意长度的号码 - 没有溢出:>>> 256 *(62 ** 100)44402652562862911414971048359760030835982580330786570771137804709455598239929932673552190201125730101070867075377228748911717860448985185350731601887476350502973424822800696272224256L (2认同)

Wol*_*lph 45

我曾经写过一个脚本来做这个,我觉得它很优雅:)

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
Run Code Online (Sandbox Code Playgroud)

用法示例:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)
Run Code Online (Sandbox Code Playgroud)

  • 这个版本比Baishampayan公认的解决方案要快得多.我通过计算函数外部的长度进一步优化.测试结果(100,000次迭代):version-WoLpH:.403 .399 .399 .398 .398 | 版本-Baishampayan:1.783 1.785 1.782 1.788 1.784.这个版本大约快4倍. (9认同)
  • 我必须将 `integer /= length` 更改为 `integer //=length` 才能获得正确的余数 (2认同)

Joh*_*hin 9

以下解码器制造商可以使用任何合理的基础,具有更加整洁的循环,并在遇到无效字符时给出明确的错误消息.

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)
Run Code Online (Sandbox Code Playgroud)


Sep*_*ero 7

如果您正在寻找最高效率(如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
Run Code Online (Sandbox Code Playgroud)

您可能还想提前计算字典.(注意:使用字符串进行编码比使用列表更有效率,即使数字非常长.)

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

在2.5秒内编码和解码100万个数字.(2.2Ghz i7-2670QM)

  • 嘿origiNell,你是对的,不需要元组(),但在我的系统上,它使代码运行速度提高了约20%.尝试在没有元组()的情况下测试它,看看什么最适合你.干杯:) (6认同)

Rya*_*Fau 5

如果您使用 django 框架,则可以使用 django.utils.baseconv 模块。

>>> from django.utils import baseconv
>>> baseconv.base62.encode(1234567890)
1LY7VK
Run Code Online (Sandbox Code Playgroud)

除了base62,baseconv还定义了base2/base16/base36/base56/base64。