2

这是我想在 Python 中实现的 Ruby 部分:

Base64.urlsafe_encode64([Digest::MD5.hexdigest(url).to_i(16)].pack("N")).sub(/==\n?$/, '')

你看,这有助于将 URL 变成这样:

http://stackoverflow.com/questions/ask

变成这样的小代码:

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 得到的要大,这个包装使用了不同的格式。

你的帮助将不胜感激。

4

3 回答 3

2

这可以解决问题:

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')只转换摘要的最后四个字节。

于 2012-04-02T03:02:30.673 回答
1

Rubypack('N')转换为网络顺序(大端)32 位无符号。pythonstruct('d')转换为 IEEE 双精度浮点数。我认为您想要在 pythonstruct('>I')中使用等效的big endian 32 位 unsigned

于 2012-04-02T02:43:18.140 回答
0

所以现在很清楚 Rubypack('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's HASH 对象的方法你得到的散列已经打包,因此使用'sdigest()将最后四个字节[-4:]用于编码就足够了。Base64urlsafe_b64encode

于 2012-04-02T04:52:02.493 回答