【问题标题】:How to hash a string into 8 digits?如何将一个字符串散列成 8 位数字?
【发布时间】:2013-04-07 04:23:45
【问题描述】:

有没有我可以在不自己实现任何算法的情况下将随机字符串散列成 8 位数字?

【问题讨论】:

  • hash("你的字符串") % 100000000
  • 8 位数似乎很小,如果您有大量记录,可能会导致哈希冲突。 stackoverflow.com/questions/1303021/…
  • 使用 hashlib,因为 hash 还有其他用途!
  • 任何有限的数字都会导致足够多的散列项发生冲突,这就是为什么您不应该将它们视为唯一键 - 它往往会变成生日问题。
  • 我选择了“CityHash”将字符串散列为 19 位长整数(64 位整数),希望这会导致比 Raymond 下面的建议更少的潜在冲突。 en.wikipedia.org/wiki/List_of_hash_functions

标签: python arrays algorithm random hash


【解决方案1】:

是的,您可以使用内置的hashlib 模块或内置的hash 功能。然后,在散列的整数形式上使用模运算或字符串切片运算去掉最后八位数字:

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

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

>>> # Use hash()
>>> abs(hash(s)) % (10 ** 8)
82148974

【讨论】:

  • 公共服务公告...这种技术实际上不会导致字符串的唯一哈希值;它计算一个哈希值,然后转换成一个非保证唯一值
  • 公共服务公告...除了在有限的输入值集上完美哈希的特殊情况,哈希函数不应该生成有保证的唯一值。
  • 你读过OP的问题吗?他(或她)想要(或需要)8 个小数位。此外,散列表的工作方式是散列到一个小的搜索空间(稀疏表)中。您似乎不知道希望散列函数通常用于并且不关心所提出的实际问题。
  • 我读了这个问题。我只是观察到,在与 SHA-1 相同的输入空间中,您的答案在天文上更有可能产生碰撞。该问题隐含地要求至少某种程度的唯一性,但您的答案是一个散列函数,其精神与为每个输入简单地返回 12345678 的散列函数相同。使用这种方法,我能够通过实验性地生成少至 1000 个输入的碰撞。要保留与 SHA-1 相同的冲突概率,您必须将未截断的 SHA-1 映射到 8 位整数。我认为这值得一个公益广告
  • 小心,哈希值不能保证在跨平台和运行时给出相同的结果。
【解决方案2】:

我正在分享由@Raymond Hettinger 实现的解决方案的nodejs 实现。

var crypto = require('crypto');
var s = 'she sells sea shells by the sea shore';
console.log(BigInt('0x' + crypto.createHash('sha1').update(s).digest('hex'))%(10n ** 8n));

【讨论】:

  • 你在一个关于 python 的问题中分享 nodejs 解决方案?
  • 是的,当我们构建系统时 - 后端使用 python 处理,而前端使用 node.js。需要确保两者无缝工作。
【解决方案3】:

只是为了完成 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

【讨论】:

    【解决方案4】:

    Raymond 的答案非常适合 python2(不过,您不需要 abs() 或 10 ** 8 左右的括号)。但是,对于 python3,有一些重要的警告。首先,您需要确保传递的是编码字符串。如今,在大多数情况下,回避 sha-1 并改用 sha-256 之类的东西可能会更好。因此,hashlib 方法是:

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

    如果你想改用 hash() 函数,重要的警告是,与 Python 2.x 不同,在 Python 3.x 中,hash() 的结果只会在进程内保持一致,而不是跨蟒蛇调用。见这里:

    $ 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
    

    这意味着建议的基于 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
    

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

    【讨论】:

    • 应该注意的是,自 Python 3.3 以来,这个答案有一个非常重要的警告,为了防止 Python 3.3 及更高版本在启动时使用随机哈希种子来防止 tar-pitting。
    • 如果数字不是您的主要要求,您也可以使用hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8] 女巫仍然会发生冲突
    • 他们应该把那个放在盒子上!
    猜你喜欢
    • 2015-12-14
    • 2020-07-14
    • 1970-01-01
    • 2022-01-16
    • 2017-05-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    相关资源
    最近更新 更多