代码之家  ›  专栏  ›  技术社区  ›  snazzybouche

在Python3中重新创建JS哈希函数

  •  0
  • snazzybouche  · 技术社区  · 7 年前

    我需要将一个散列函数从JavaScript转换成Python。

    其功能如下:

    function getIndex(string) {
            var length = 27;
            string = string.toLowerCase();
            var hash = 0;
            for (var i = 0; i < string.length; i++) {
                    hash = string.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;
            }
            var index = Math.abs(hash % length);
            return index;
    }
    
    console.log(getIndex(window.prompt("Enter a string to hash")));

    这个函数在客观上是正确的。它本身就是完美。我不能改变它,我只能重新创造它。无论它输出什么,我的Python脚本也必须输出。

    然而,我有几个问题,我认为这都与这两种语言处理有符号整数的方式有关。

    JS位运算符将其操作数视为32位序列。然而,Python并没有位限制的概念,只是像个十足的疯子一样继续前进。我认为这就是两种语言之间的一个相关区别。

    我可以限制 hash 在Python中,通过使用 hash & 0xFFFFFFFF .

    我也可以否定 搞砸 0x7FFFFFFF 具有 hash = hash ^ 0xFFFFFFFF (或 hash = ~hash

    我用一个名为 t .

    以下是迄今为止我的Python代码:

    def nickColor(string):
        length = 27
    
        def t(x):
            x = x & 0xFFFFFFFF
            if x > 0x7FFFFFFF:
                x = x ^ 0xFFFFFFFF
            return x
    
        string = string.lower()
        hash = t(0)
        for letter in string:
            hash = t(hash)
            hash = t(t(ord(letter)) + t(hash << 6) + t(hash << 16) - t(hash))
        index = hash % length
        return index
    

    它似乎一直在工作,直到哈希值需要变为负,此时两个脚本就会出现分歧。这通常发生在字符串中大约4个字母。

    我假设我的问题在于在Python中重新创建JS负数。我怎样才能告别这个问题呢?

    0 回复  |  直到 7 年前
        1
  •  4
  •   Walter Tross    7 年前

    这里有一个工作翻译:

    def nickColor(string):
        length = 27
    
        def t(x):
            x &= 0xFFFF_FFFF
            if x > 0x7FFF_FFFF:
                x -= 0x1_0000_0000
            return float(x)
    
        bytes = string.lower().encode('utf-16-le')
        hash = 0.0
        for i in range(0, len(bytes), 2):
            char_code = bytes[i] + 256*bytes[i+1]
            hash = char_code + t(int(hash) << 6) + t(int(hash) << 16) - hash
        return int(hash % length if hash >= 0 else abs(hash % length - length))
    

    << )计算为32位整数运算,其结果为 converted back to double 在输入加减法之前。我不熟悉两种语言中双精度浮点表示的规则,但可以肯定的是,在所有个人计算设备和web服务器上,这两种语言都是相同的,即 double-precision IEEE 754 . 对于非常长的字符串(数千个字符),哈希可能会丢失一些精度,这当然会影响最终结果,但在JS中与在Python中的方式相同(这不是客观正确函数的作者想要的,但事实就是如此)。最后一行更正了 % 中负操作数的运算符 JavaScript Python .

    此外(感谢Mark Ransom提醒我这一点),要完全模拟JavaScript,还需要考虑它的编码,即UTF-16,但是 surrogate pairs 像是由两个字符组成。将字符串编码为 utf-16-le 你要确保每个16位字中的第一个字节是最不重要的,另外,你没有得到 BOM 如果你用 utf-16 tout court(谢谢Martijn Pieters)。