在Python中为URL参数生成固定长度的哈希

11 投票
2 回答
6644 浏览
提问于 2025-04-15 21:21

我正在使用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

撰写回答