这是我想在Python:中实现的Ruby
Base64.urlsafe_encode64([Digest::MD5.hexdigest(url).to_i(16)].pack("N")).sub(/==n?$/, '')
你看,这有助于打开这样的URL:
http://stackoverflow.com/questions/ask
转换成这样的小代码e:
sUEBtw
在这个过程中生成的大整数是:
307275247029202263937236026733300351415
我已经能够使用以下Python代码将其打包为二进制形式:
url = 'http://stackoverflow.com/questions/ask'
n = int(hashlib.md5(url).hexdigest(), 16)
s = struct.Struct('d')
values = [n]
packed_data = s.pack(*values)
short_code = base64.urlsafe_b64encode(packed_data)[:-1]
print short_code
我得到的短代码是:
zgMM62Hl7Ec
正如你所看到的,它比我用Ruby得到的要大——这个包装使用了不同的格式。
您的帮助将不胜感激。
这就完成了任务:
import hashlib
import base64
url = 'http://stackoverflow.com/questions/ask'
print base64.urlsafe_b64encode(hashlib.md5(url).digest()[-4:])[:-2]
输出
sUEBtw
.digest()
给出了完整的16字节摘要的压缩字节,因此不需要struct.pack
,但Ruby的.pack('N')
似乎只转换摘要的最后四个字节。
pack('N')
转换为32位无符号的网络订单(big-endian)。python struct('d')
转换为IEEE双精度浮点。我想您需要struct('>I')
作为python中等效的32位无符号大端序。
所以现在很明显,Ruby的pack('N')
只占用较低的4个字节,所以根据DSM的建议,我可以使用以下代码:
import hashlib
import base64
url = 'https://stackoverflow.com/questions/ask'
n = int(hashlib.md5(url).hexdigest(), 16)
s = struct.Struct('>I')
values = [n % (2**32)]
packed_data = s.pack(*values)
print base64.urlsafe_b64encode(packed_data)[:-2]
尽管如此,正如Mark Tolonen的回答中所解释的,hashlib
的HASH对象的digest()
方法已经打包了哈希,所以用[-4:]
的最后四个字节使用Base64
的urlsafe_b64encode
进行编码就足够了。