2010-03-24 2 views
16

Я хотел бы установить нецелые первичные ключи для таблицы, используя какую-либо хеш-функцию. md5() кажется длинным (32 символа).Короткий алфавитно-цифровой хэш-код Python с минимальными коллизиями

Каковы некоторые альтернативные хеш-функции, которые, возможно, используют каждую букву в алфавите, а также целые числа, которые, возможно, короче длины строки и имеют низкие скорости столкновений?

Спасибо!

ответ

15

Почему бы вам просто не урезать SHA1 или MD5? Тогда у вас будет больше коллизий, если вы не усекаетесь, но это все же лучше, чем создание собственного. Обратите внимание, что вы можете base64-кодировать усеченный хэш, а не использовать шестнадцатеричный. Например.

import base64 
import hashlib 
hasher = hashlib.sha1("The quick brown fox") 
base64.urlsafe_b64encode(hasher.digest()[0:10]) 

Вы можете укоротить, как мало (в том числе и не на всех) или столько, сколько вы хотите, до тех пор, как вы понимаете компромиссы.

EDIT: Поскольку вы упомянули URL-сейф, вы можете использовать и urlsafe_b64decode, который использует - и _, а не + и /.

+0

Спасибо. Есть ли какая-либо низкоуровневая буквенно-цифровая хеш-функция, менее 16 символов, что не связано с усечением? Спасибо. – ensnare

+3

Почему вы не хотите усекать? –

+1

Вы также можете удалить все символы '=', добавленные в конец. Они существенно не уменьшают скорость столкновения, но они добавляют два символа. Возможно, что-то вроде: 'base64.urlsafe_b64encode (hasher.digest() [0:10]). Replace ('=', '')' – speedplane

17

Самый маленький встроенный хэш Я знаю это md5

>>> import hashlib 
>>> hashlib.md5("hello worlds").digest().encode("base64") 
'uWuHitcvVnCdu1Yo4c6hjQ==\n' 

Низкая коллизия и короткие несколько взаимоисключающих благодаря birthday paradox

Чтобы сделать это 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' 
>>> base64.urlsafe_b64encode(md5bytes) 
'XrY7u-Ae7tCTyyK7j1rNww==' 

Вы можете выбрать либо quote_plus или urlsafe_b64encode для URL, а затем декодировать с соответствующей функцией unquote_plus или urlsafe_b64decode, прежде чем искать их в базе данных.

+0

Спасибо. Как я могу сделать это urlsafe? – ensnare

3

Ниже приведено решение, в котором используются буквенно-цифровые символы и несколько знаков препинания. Он возвращает очень короткие строки (около 8 символов).

import binascii, struct 

def myhash(s): 
    return binascii.b2a_base64(struct.pack('i', hash(s))) 
+1

'hash (s)' дает другой результат для 32/64 бит-платформ. –

+1

@gnibbler. Вопрос не отображает согласованность между платформами как требование. –

0

Вы можете использовать что-то вроде обозначения базовой 32. Он более компактен, чем десятичная нотация, без учета регистра и без столкновений. Просто закодируйте простой старый порядковый номер, чтобы создать короткий хэш-код.

Если ключ не предназначен для потребления человеком, вы можете использовать нотацию base 64, которая чувствительна к регистру, но немного более компактна.

См. Например, http://code.google.com/p/py-cupom/.

2

Hashids - это библиотека (с поддержкой Python), которая создает хэши, которые вы можете легко кодировать/декодировать.

http://hashids.org/python/

Смежные вопросы