如何将字符串哈希为8位数?

dor*_*mon 70 python arrays random algorithm hash

无论如何我是否可以将随机字符串散列为8位数而不自行实现任何算法?

Ray*_*ger 113

是的,您可以使用内置的hashlib模块或内置的哈希函数.然后,在整数形式的散列上使用模运算或字符串切片操作来切断最后八位数:

>>> s = 'she sells sea shells by the sea shore'

>>> # Use hashlib
>>> import hashlib
>>> int(hashlib.sha1(s).hexdigest(), 16) % (10 ** 8)
58097614L

>>> # Use hash()
>>> abs(hash(s)) % (10 ** 8)
82148974
Run Code Online (Sandbox Code Playgroud)

  • 公共服务公告...除了在有限的输入值集合上完美哈希的特殊情况之外,哈希函数不应该生成有保证的唯一值. (71认同)
  • 公共服务公告......这种技术实际上并不会导致字符串的唯一哈希值; 它计算一个哈希,然后进入一个非保证唯一值 (18认同)
  • 我读了这个问题.我只是在与SHA-1相同的输入空间观察,你的答案在天文学上更有可能产生碰撞而不是.问题隐含地要求至少某种程度的唯一性,但你的答案是一个哈希函数,其精神与为每个输入简单地返回12345678的哈希函数相同.我能够使用这种方法通过实验产生一个只有1000个输入的碰撞.为了保持与SHA-1相同的冲突概率,您必须将未截断的SHA-1映射到8位整数.我认为这值得PSA (15认同)
  • 小心,散列(s)并不能保证在平台和运行中提供相同的结果. (14认同)
  • 你读过OP的问题了吗?他(或她)想要(或需要)8位小数.此外,散列表的工作方式是散列到一个小的搜索空间(稀疏表).你好像不知道想要哈希函数是常用的,也不关心被问到的实际问题. (5认同)
  • 可能是真的,但实际上它们的所有实用性都源于它们产生独特价值的良好倾向.使用此技巧进行"哈希"冲突的概率可能比md5高出10或11个数量级 (4认同)
  • 需要`abs`吗?Modulo应该返回一个正int. (3认同)
  • 一个重要的警告是,与 Python 2.x 不同,hash(x) 在每次 Python 3.x 解释器调用时返回不同的值(它在单个进程中是一致的)。因此,如果 OP 依赖于跨脚本运行的给定字符串的哈希值相同,则后者在 Python 3.x 中将不起作用。这只是咬我。我将添加一个答案以反映这两条评论(尚不确定编辑礼仪)。 (3认同)
  • @silgon Python的窥孔优化器会不断进行折叠,因此计算仅执行一次。这很容易验证。运行``dis(compile('10 ** 8',``,'eval')))并查找片段``LOAD_CONST 0(100000000)''。或者,运行``def f():return 10 ** 8''并观察到``f .__ code __。co_consts``返回``(None,100000000)``。请注意,“ 10E8”不是有效的替代物,因为这是* float *而不是* int *。 (2认同)

JJC*_*JJC 63

雷蒙德的答案对于python2来说很棒(但是,你不需要abs()也不需要10**8左右的parens).但是,对于python3,有一些重要的警告.首先,您需要确保传递编码的字符串.这些天来,在大多数情况下,回避sha-1并使用像sha-256这样的东西也可能更好.因此,hashlib方法将是:

>>> import hashlib
>>> s = 'your string'
>>> int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16) % 10**8
80262417
Run Code Online (Sandbox Code Playgroud)

如果你想使用hash()函数,重要的警告是,与Python 2.x不同,在Python 3.x中,hash()的结果只在进程内是一致的,而不是在python调用中.看这里:

$ python -V
Python 2.7.5
$ python -c 'print(hash("foo"))'
-4177197833195190597
$ python -c 'print(hash("foo"))'
-4177197833195190597

$ python3 -V
Python 3.4.2
$ python3 -c 'print(hash("foo"))'
5790391865899772265
$ python3 -c 'print(hash("foo"))'
-8152690834165248934
Run Code Online (Sandbox Code Playgroud)

这意味着建议使用基于hash()的解决方案,该解决方案可以简化为:

hash(s) % 10**8

只会在给定的脚本运行中返回相同的值:

#Python 2:
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543

#Python 3:
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
12954124
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
32065451
Run Code Online (Sandbox Code Playgroud)

因此,根据您的应用程序(在我的应用程序中)是否重要,您可能希望坚持基于hashlib的方法.

  • 应该注意的是,这个答案自 Python 3.3 以来有一个非常重要的警告,以防止 Python 3.3 及更高版本在启动时使用随机哈希种子。 (5认同)

小智 12

从 Python 3.10 开始,将字符串哈希为 8 个十六进制数字摘要的另一种快速方法是使用shake.hexdigest(4)

import hashlib
h=hashlib.shake_128(b"my ascii string").hexdigest(4)
#34c0150b
Run Code Online (Sandbox Code Playgroud)

注意 4 而不是 8,因为摘要的长度是作为参数给出的数字的两倍。

当然要注意哈希冲突。


小智 9

只是为了完成 JJC 答案,在 python 3.5.3 中,如果您以这种方式使用 hashlib,则行为是正确的:

$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded
$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded

$ python3 -V
Python 3.5.3
Run Code Online (Sandbox Code Playgroud)