我想使用某种哈希函数为表设置非整数主键。 md5()似乎有点长(32个字符)。
哪些替代哈希函数可能使用字母表中的每个字母以及字符串长度较短且碰撞率较低的整数?
谢谢!
答案 0 :(得分:23)
为什么不截断SHA1或MD5?如果你没有截断,你会有更多的碰撞,但它仍然比设计你自己更好。请注意,您可以对截断的哈希进行base64编码,而不是使用十六进制。 E.g。
import base64
import hashlib
hasher = hashlib.sha1("The quick brown fox")
base64.urlsafe_b64encode(hasher.digest()[:10])
只要您了解权衡,就可以截断尽可能少(包括根本没有)或尽可能多的截断。
编辑:由于您提到了网址安全,因此您可以使用urlsafe_b64encode和urlsafe_b64decode,它使用-
和_
而不是+
和{{ 1}}。
答案 1 :(得分:22)
我所知道的最小的内置哈希是md5
>>> import hashlib, base64
>>> d=hashlib.md5(b"hello worlds").digest(); d=base64.b64encode(d);
>>> print(d)
b'S27ylES0wiLdFAGdUpFgCQ=='
,低碰撞和短碰撞有些相互排斥
要使其成为urlsafe,您需要使用base64模块中的函数
>>> import base64
>>> base64.urlsafe_b64encode(hashlib.md5("hello world").digest())
'XrY7u-Ae7tCTyyK7j1rNww=='
但是,以二进制形式在数据库中存储16字节md5摘要应该没有问题。
>>> md5bytes=hashlib.md5("hello world").digest()
>>> len(md5bytes)
16
>>> urllib.quote_plus(md5bytes)
'%5E%B6%3B%BB%E0%1E%EE%D0%93%CB%22%BB%8FZ%CD%C3'
Python 2
>>> base64.urlsafe_b64encode(md5bytes)
'XrY7u-Ae7tCTyyK7j1rNww=='
Python 3
>>> base64.urlsafe_b64encode(md5bytes).decode('ascii')
'XrY7u-Ae7tCTyyK7j1rNww=='
您可以为您的网址选择quote_plus
或urlsafe_b64encode
,然后使用相应的功能unquote_plus
或urlsafe_b64decode
进行解码,然后再在数据库中查找它们。
答案 2 :(得分:3)
以下是使用字母数字字符加上一些标点字符的解决方案。它返回非常短的字符串(大约8个字符)。
import binascii, struct
def myhash(s):
return binascii.b2a_base64(struct.pack('i', hash(s)))
答案 3 :(得分:3)
Hashids是一个库(支持Python),可以创建可以轻松编码/解码的哈希值。
答案 4 :(得分:0)
你可以使用类似base 32的表示法。它比十进制表示法更紧凑,不区分大小写且无冲突。只需编码一个普通的旧序列号即可生成一个类似哈希的短代码。
如果该键不供人类使用,您可以使用base 64表示法,它区分大小写,但更紧凑。
有关示例,请参阅http://code.google.com/p/py-cupom/。