Короткий алфавитно-цифровой хэш-код Python с минимальными коллизиями
Я хотел бы установить нецелые первичные ключи для таблицы, используя какую-то хеш-функцию. md5() кажется длинным (32 символа).
Каковы некоторые альтернативные хеш-функции, которые, возможно, используют каждую букву в алфавите, а также целые числа, которые, возможно, короче длины строки и имеют низкие скорости столкновений?
Спасибо!
Ответы
Ответ 1
Почему бы вам просто не обрезать SHA1 или MD5? У вас будет больше коллизий, чем если бы вы не усекались, но это все же лучше, чем разрабатывать свои собственные. Обратите внимание, что вы можете base64-кодировать усеченный хеш, а не использовать шестнадцатеричный. Например
import base64
import hashlib
hasher = hashlib.sha1("The quick brown fox")
base64.urlsafe_b64encode(hasher.digest()[:10])
Вы можете усекать как можно меньше (в том числе и вовсе) или столько, сколько хотите, если вы понимаете компромисс.
РЕДАКТИРОВАТЬ: Так как вы упомянули URL-безопасный, вы можете использовать urlsafe_b64encode и urlsafe_b64decode, который использует -
и _
вместо +
и /
.
Ответ 2
Самый маленький встроенный хеш, который я знаю, это 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=='
Вы можете выбрать для вашего URL либо quote_plus
либо urlsafe_b64encode
, а затем декодировать с помощью соответствующей функции unquote_plus
или urlsafe_b64decode
прежде чем искать их в базе данных.
Ответ 3
Ниже приведено решение, которое использует буквенно-цифровые символы плюс несколько знаков препинания. Он возвращает очень короткие строки (около 8 символов).
import binascii, struct
def myhash(s):
return binascii.b2a_base64(struct.pack('i', hash(s)))
Ответ 4
Hashids - это библиотека (с поддержкой Python), которая создает хэши, которые вы можете легко кодировать/декодировать.
http://hashids.org/python/
Ответ 5
Вы можете использовать что-то вроде нотации базы 32. Он более компактен, чем десятичная нотация, без учета регистра и без столкновений. Просто закодируйте простой старый порядковый номер, чтобы создать короткий хэш-код.
Если ключ не предназначен для потребления человеком, вы можете использовать нотацию base 64, которая чувствительна к регистру, но немного более компактна.
См. http://code.google.com/p/py-cupom/ для примера.