Python Unicode ASCII,序数超出范围,令人沮丧的错误

3 投票
3 回答
5829 浏览
提问于 2025-04-17 12:48

这是我的问题……

数据库里的所有内容都是用unicode格式存储的。

hashlib.sha256().digest()这个函数接受字符串并返回字符串。

当我试图用数据来计算哈希值时,出现了著名的错误:

UnicodeDecodeError: 'ascii' codec can't decode byte 0x90 in position 1: ordinal not in range(128)

这是我的数据

>>> db_digest
u"'\x90\x017~1\xe0\xaf4\xf2\xec\xd5]:j\xef\xe6\x80\x88\x89\xfe\xf7\x99,c\xff\xb7\x06hXR\x99\xad\x91\x93lM:\xafT\xc9j\xec\xc3\xb7\xea[\x80\xe0e\xd6\\\xd8\x16'\xcb6\xc8\xaa\xdf\xc9 :\xff"
>>> 
>>> hashlib.sha256(db_digest)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\x90' in position 1: ordinal not in range(128)
>>> 
>>> asc_db_digest
"'\x90\x017~1\xe0\xaf4\xf2\xec\xd5]:j\xef\xe6\x80\x88\x89\xfe\xf7\x99,c\xff\xb7\x06hXR\x99\xad\x91\x93lM:\xafT\xc9j\xec\xc3\xb7\xea[\x80\xe0e\xd6\\\xd8\x16'\xcb6\xc8\xaa\xdf\xc9 :\xff"
>>> hashlib.sha256(asc_db_digest)
<sha256 HASH object @ 0x7f7da0f04300>

所以我想要的就是找到一种方法,把db_digest转换成asc_db_digest。

编辑 我重新表述了一下问题,因为我发现自己一开始没有正确理解问题。

3 个回答

1

这个哈希值会包含一些“字符”,它们的范围是0到255。这些都是有效的Unicode字符,但它并不是一个Unicode字符串。你需要以某种方式进行转换。最好的办法是把它编码成像base64这样的格式。

还有一种比较“hacky”的方法,可以直接把返回的字节转换成一个伪Unicode字符串,正如你的数据库似乎在做的那样:

hash_unicode = u''.join([unichr(ord(c)) for c in hash_digest])

你也可以反过来做,但这样更危险,因为这个“字符串”会包含一些超出ASCII范围(0-127)的字符,使用时可能会出错。

asc_db_digest = ''.join([chr(ord(c)) for c in db_digest])
3

哈希函数是处理字节的(在Python 2.x中是bytesstr),而不是处理字符串的(在2.x中是unicode,在3.x中是str)。所以,你必须提供字节。可以试试:

hashlib.sha1(salt.encode('utf-8') + data).digest()
5

如果你有一个只包含从0到255(字节)的unicode字符串,你可以使用raw_unicode_escape编码把它转换成Python的字符串:

>>> db_digest = u"'\x90\x017~1\xe0\xaf4\xf2\xec\xd5]:j\xef\xe6\x80\x88\x89\xfe\xf7\x99,c\xff\xb7\x06hXR\x99\xad\x91\x93lM:\xafT\xc9j\xec\xc3\xb7\xea[\x80\xe0e\xd6\\\xd8\x16'\xcb6\xc8\xaa\xdf\xc9 :\xff"
>>> hash_digest = "'\x90\x017~1\xe0\xaf4\xf2\xec\xd5]:j\xef\xe6\x80\x88\x89\xfe\xf7\x99,c\xff\xb7\x06hXR\x99\xad\x91\x93lM:\xafT\xc9j\xec\xc3\xb7\xea[\x80\xe0e\xd6\\\xd8\x16'\xcb6\xc8\xaa\xdf\xc9 :\xff"
>>> db_digest.encode('raw_unicode_escape')
"'\x90\x017~1\xe0\xaf4\xf2\xec\xd5]:j\xef\xe6\x80\x88\x89\xfe\xf7\x99,c\xff\xb7\x06hXR\x99\xad\x91\x93lM:\xafT\xc9j\xec\xc3\xb7\xea[\x80\xe0e\xd6\\\xd8\x16'\xcb6\xc8\xaa\xdf\xc9 :\xff"
>>> db_digest.encode('raw_unicode_escape') == hash_digest
True

撰写回答