如何使用 Python 打包一个大整数,将四个字符视为网络字节顺序中的无符号长整型,就像 Ruby 的 .pack( "N" ) 所做的那样?



这是我想在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')似乎只转换摘要的最后四个字节。

Ruby 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:]的最后四个字节使用Base64urlsafe_b64encode进行编码就足够了。

相关内容

  • 没有找到相关文章

最新更新