当前位置:  开发笔记 > 编程语言 > 正文

如何在Python中将整数转换为最短的url-safe字符串?

如何解决《如何在Python中将整数转换为最短的url-safe字符串?》经验,为你挑选了6个好方法。

我想要一种在URL中表示整数的最短方式.例如,11234可以使用十六进制缩短为"2be2".由于base64使用的是64字符编码,因此应该可以使用比十六进制更少的字符来表示base64中的整数.问题是我无法弄清楚使用Python将整数转换为base64(以及再返回)的最简洁方法.

base64模块有处理字节串的方法 - 所以也许一个解决方案是将一个整数转换为二进制表示形式作为Python字符串...但我不知道如何做到这一点.



1> Miles..:

这个答案与Douglas Leeder的精神相似,但有以下变化:

它不使用实际的Base64,因此没有填充字符

它不是首先将数字转换为字节串(基数256),而是将其直接转换为base 64,这样可以让您使用符号字符表示负数.

import string
ALPHABET = string.ascii_uppercase + string.ascii_lowercase + \
           string.digits + '-_'
ALPHABET_REVERSE = dict((c, i) for (i, c) in enumerate(ALPHABET))
BASE = len(ALPHABET)
SIGN_CHARACTER = '$'

def num_encode(n):
    if n < 0:
        return SIGN_CHARACTER + num_encode(-n)
    s = []
    while True:
        n, r = divmod(n, BASE)
        s.append(ALPHABET[r])
        if n == 0: break
    return ''.join(reversed(s))

def num_decode(s):
    if s[0] == SIGN_CHARACTER:
        return -num_decode(s[1:])
    n = 0
    for c in s:
        n = n * BASE + ALPHABET_REVERSE[c]
    return n


    >>> num_encode(0)
    'A'
    >>> num_encode(64)
    'BA'
    >>> num_encode(-(64**5-1))
    '$_____'

一些附注:

您可以(略微)通过将string.digits放在字母表中(并使符号字符' - ')来增加base-64数字的人类可读性; 我根据Python的urlsafe_b64encode选择了我的订单.

如果你编码了很多负数,你可以通过使用符号位或一个/两个补码而不是符号字符来提高效率.

您应该能够通过更改字母表轻松地将此代码调整到不同的基础,或者将其限制为仅包含字母数字字符或添加其他"URL安全"字符.

在大多数情况下,我建议不要在URI中使用基本10以外的表示 - 它增加了复杂性,并且与HTTP的开销相比,调试更加困难而且没有显着的节省 - 除非你想要TinyURL-esque.


@hwiechers:`s`实际上不是一个字符串,它是一个列表,所以我仍然要加入它; 我可以做'.'.join(s [:: - 1])`或`''.join(s)[:: - 1]`,但那些只是稍微快一点 - 远远低于看到的数量级在telliott99的微基准测试中用于反转字符串.

2> Alexander Lj..:

关于Base64的所有答案都是非常合理的解决方案.但它们在技术上是不正确的.要将整数转换为可能的最短URL安全字符串,您需要的是base 66(有66个URL安全字符).

该代码如下所示:

from io import StringIO
import urllib

BASE66_ALPHABET = u"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~"
BASE = len(BASE66_ALPHABET)

def hexahexacontadecimal_encode_int(n):
    if n == 0:
        return BASE66_ALPHABET[0].encode('ascii')

    r = StringIO()
    while n:
        n, t = divmod(n, BASE)
        r.write(BASE66_ALPHABET[t])
    return r.getvalue().encode('ascii')[::-1]

这是一个完整的实现源代码,可以随时使用pip可安装包:

https://github.com/aljungberg/hexahexacontadecimal



3> Brian..:

你可能不需要真正的base64编码 - 它会添加填充等,甚至可能导致比小数字更大的字符串.如果不需要与其他任何东西进行互操作,只需使用您自己的编码即可.例如.这是一个将编码到任何基数的函数(注意数字实际上是存储最不重要的,以避免额外的reverse()调用:

def make_encoder(baseString):
    size = len(baseString)
    d = dict((ch, i) for (i, ch) in enumerate(baseString)) # Map from char -> value
    if len(d) != size:
        raise Exception("Duplicate characters in encoding string")

    def encode(x):
        if x==0: return baseString[0]  # Only needed if don't want '' for 0
        l=[]
        while x>0:
            l.append(baseString[x % size])
            x //= size
        return ''.join(l)

    def decode(s):
        return sum(d[ch] * size**i for (i,ch) in enumerate(s))

    return encode, decode

# Base 64 version:
encode,decode = make_encoder("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")

assert decode(encode(435346456456)) == 435346456456

这样做的好处是,只需向编码器的基本字符串添加适当的字符,即可使用所需的任何基础.

请注意,较大基数的收益不会那么大.base 64只会将大小减小到base 16的2/3rds(6位/ char而不是4位).每次加倍只会为每个字符增加一位.除非你真的需要压缩东西,否则只使用十六进制可能是最简单和最快的选择.



4> kmkaplan..:

编码n:

data = ''
while n > 0:
    data = chr(n & 255) + data
    n = n >> 8
encoded = base64.urlsafe_b64encode(data).rstrip('=')

要解码s:

data = base64.urlsafe_b64decode(s + '===')
decoded = 0
while len(data) > 0:
    decoded = (decoded << 8) | ord(data[0])
    data = data[1:]

与其他一些"最佳"编码一样,您可以根据RFC 1738 使用73个字符(如果您将"+"视为可用,则实际为74个):

alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_`\"!$'()*,-."
encoded = ''
while n > 0:
    n, r = divmod(n, len(alphabet))
    encoded = alphabet[r] + encoded

和解码:

decoded = 0
while len(s) > 0:
    decoded = decoded * len(alphabet) + alphabet.find(s[0])
    s = s[1:]



5> Douglas Leed..:

简单的一点是将字节字符串转换为Web安全的base64:

import base64
output = base64.urlsafe_b64encode(s)

棘手的位是第一步 - 将整数转换为字节串.

如果你的整数很小,你最好用十六进制编码它们 - 见saua

否则(hacky递归版):

def convertIntToByteString(i):
    if i == 0:
        return ""
    else:
        return convertIntToByteString(i >> 8) + chr(i & 255)



6> Øystein E. K..:

您不需要base64编码,您希望在数字基数X中表示基数为10的数字.

如果您希望您的基数10数字以26个字母表示,您可以使用:http: //en.wikipedia.org/wiki/Hexavigesimal.(您可以通过使用所有合法的URL字符将该示例扩展为更大的基础)

你应该至少能得到38(26个字母,10个数字,+,_)

推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有