在Python中为URL参数生成固定长度的哈希
我正在使用Python在App Engine上工作。
我想创建一个类似于YouTube网址中“v”后面的值(比如http://www.youtube.com/watch?v=XhMN0wlITLk)的东西,用来获取特定的实体。数据存储会自动生成一个键,但这个键太长了,有34位。我尝试使用hashlib来生成自己的键,但结果还是得到了一串很长的字符串。我希望能把它控制在11位以内(因为我处理的实体数量不多),字母和数字都可以。
看起来应该有一个比较标准的解决方案。我可能只是没找到。
2 个回答
7
如果你有一个每个实体都独一无二的值,你可以通过哈希处理和截断来得到一个更短的版本。像md5或sha1这样的哈希算法是经过良好混合的,这意味着如果你改变输入中的一个位,输出中的每一位都有50%的机会会发生变化。截断哈希值只是增加了碰撞的可能性,但你可以在长度和碰撞概率之间做出权衡。
使用安全的url base64编码是将哈希值转换为文本的一个不错选择。
orig_id = 'weiowoeiwoeciw0eijw0eij029j20d232weifw0jiw0e20d2' # the original id
shorter_id = base64.urlsafe_b64encode(hashlib.md5(orig_id).digest())[:11]
使用base64编码时,每个字符包含6位信息,11个字符可以提供66位的独特性,也就是说碰撞的概率是1比2的66次方。
8
你可以使用自动生成的整数ID来生成哈希值。生成哈希值的一个简单方法是把这个整数ID转换成62进制(也就是字母和数字的组合)。要获取对象时,只需将62进制转换回十进制,然后使用get_by_id来取回对象。
下面是我在一个应用中用过的简单的62进制转换函数。
import string
alphabet = string.letters + string.digits
max = 11
def int_to_base62(num):
if num == 0:
return alphabet[0]
arr = []
radix = len(alphabet)
while num:
arr.append(alphabet[num%radix])
num /= radix
arr.reverse()
return (alphabet[0] * (max - len(arr))) + ''.join(arr)
def base62_to_int(str):
radix = len(alphabet)
power = len(str) - 1
num = 0
for char in str:
num += alphabet.index(char) * (radix ** power)
power -= 1
return num