Как использовать хеш MD5 (или другие двоичные данные) в качестве имени ключа? - PullRequest
5 голосов
/ 22 декабря 2010

Я пытался использовать хеш MD5 в качестве имени ключа в AppEngine, но код, который я написал, вызывает UnicodeDecodeError

from google.appengine.ext import db
import hashlib
key = db.Key.from_path('Post', hashlib.md5('thecakeisalie').digest())

Я не хочу использовать hexdigest() как таковойне только кладж, но и низший (base64 сделает лучше).

Ответы [ 5 ]

12 голосов
/ 22 декабря 2010

App Engine Python docs говорит:

Имя ключа сохраняется в виде строки Unicode (со значениями str, преобразованными в текст ASCII).

Ключ должен быть строкой, кодируемой Unicode.Вам нужно изменить вызов digest () на hexdigest (), то есть:

k = hashlib.md5('thecakeisalie').hexdigest()
5 голосов
/ 07 января 2011

декодирует байтовую строку с помощью iso-8859-1

>>> hashlib.md5('thecakeisalie').digest().decode("iso-8859-1")
u"'\xfc\xce\x84h\xa9\x1e\x8a\x12;\xa5\xb1K\xea\xef\xd6"

Это в основном преобразование "NOP".Он создает объект Unicode такой же длины, что и исходная строка, и может быть преобразован обратно в строку просто на .encode("iso-8859-1"), если вы хотите

4 голосов
/ 07 января 2011

Давайте подумаем о размерах данных. Оптимальное решение здесь составляет 16 байтов:

>>> hashlib.md5('thecakeisalie').digest() 
"'\xfc\xce\x84h\xa9\x1e\x8a\x12;\xa5\xb1K\xea\xef\xd6"

>>> len(hashlib.md5('thecakeisalie').digest())
16

Первое, о чем вы подумали, был hexdigest, но он не очень близок к 16 байтам:

>>> hashlib.md5('thecakeisalie').hexdigest() 
'27fcce8468a91e8a123ba5b14beaefd6'

>>> len(hashlib.md5('thecakeisalie').hexdigest())
32

Но это не даст вам ascii-кодируемых байтов, поэтому мы должны сделать что-то еще. Простая вещь, которую нужно сделать, это использовать представление python:

>>> repr(hashlib.md5('thecakeisalie').digest())
'"\'\\xfc\\xce\\x84h\\xa9\\x1e\\x8a\\x12;\\xa5\\xb1K\\xea\\xef\\xd6"'

>>> len(repr(hashlib.md5('thecakeisalie').digest()))
54

Мы можем избавиться от всего этого, удалив символы "\ x" и окружающие кавычки:

>>> repr(hashlib.md5('thecakeisalie').digest())[1:-1].replace('\\x','')
"'fcce84ha91e8a12;a5b1Keaefd6"

>>> len(repr(hashlib.md5('thecakeisalie').digest())[1:-1].replace('\\x',''))
28

Это довольно хорошо, но base64 работает немного лучше:

>>> base64.b64encode(hashlib.md5('thecakeisalie').digest())
J/zOhGipHooSO6WxS+rv1g==
>>> len(base64.b64encode(hashlib.md5('thecakeisalie').digest()))
24

В целом, base64 наиболее экономичен, но я бы просто использовал hexdigest, поскольку он наиболее оптимизирован (эффективен по времени).


Ответ Гнибблера дает длину 16!

>>> hashlib.md5('thecakeisalie').digest().decode("iso-8859-1")
u"'\xfc\xce\x84h\xa9\x1e\x8a\x12;\xa5\xb1K\xea\xef\xd6"
>>> len(hashlib.md5('thecakeisalie').digest().decode("iso-8859-1"))
16
1 голос
/ 19 января 2011

Ключ сущности в App Engine может иметь либо идентификатор (4-байтовое целое число), либо имя (500-байтовая строка в кодировке UTF-8).

Дайджест MD5 - это 16 байт двоичных данных: слишком большой для целого числа (вероятно, будет) недействительным UTF-8. Некоторая форма кодирования должна быть использована.

Если hexdigest () слишком многословен на 32 байта, тогда попробуйте base64 на 24 байта.

Какую бы схему кодирования вы не использовали, она в конечном итоге будет преобразована в UTF-8 хранилищем данных, поэтому следующее, которое на первый взгляд выглядит как оптимальное кодирование ...

>>> u = hashlib.md5('thecakeisalie').digest().decode("iso-8859-1")
>>> len(u)
16

... при кодировании в его окончательное представление на два байта длиннее, чем в кодировке base64:

>>> s = u.encode('utf-8')
>>> len(s)
26
1 голос
/ 22 декабря 2010

Я считаю использование кодировки base64 двоичных данных разумным решением. На основе вашего кода вы можете сделать что-то вроде:

import hashlib
import base64
print base64.b64encode(hashlib.md5('thecakeisalie').digest())
...