在Python和Node.js中复现java.lang.String.hashCode()输出的函数

8 投票
2 回答
4762 浏览
提问于 2025-04-18 01:13

我正在尝试在 Node.js 和 Python 中实现一个函数,用来生成与 Java 的 hashCode 相同的值,以便进行 Redis 分片。我在参考一篇很不错的博客,链接在这里:http://mechanics.flite.com/blog/2013/06/27/sharding-redis/

但是我遇到了一个问题,就是当字符串中包含一些非 ASCII 字符时,hashCode 的计算结果会有所不同。对于普通字符串,我可以得到 Node.js 和 Python 都给出相同的 hashCode。

这是我用来生成 hashCode 的代码:

--Python

def _java_hashcode(s):
    hash_code = 0
    for char in s:
        hash_code = 31*h + ord(char)

    return ctypes.c_int32(h).value   

--根据上面的博客的 Node.js 代码

String.prototype.hashCode = function() {
  for(var ret = 0, i = 0, len = this.length; i < len; i++) {
    ret = (31 * ret + this.charCodeAt(i)) << 0;
  }
  return ret;
};

--Python 输出结果

For string '者:s��2�*�=x�' hash is = 2014651066
For string '359196048149234' hash is = 1145341990

--Node 输出结果

For string '者:s��2�*�=x�' hash is = 150370768
For string '359196048149234' hash is = 1145341990

请帮我看看,我哪里出错了……我是否需要在 Python 和 Node 程序中设置某种编码?我尝试了一些,但我的 Python 程序就出错了。

2 个回答

0

在Python 2中,如果不特别说明,它会默认使用ASCII编码。自从有了PEP 0263这个规范后,你可以在文件的顶部添加以下内容来指定使用utf-8编码的字符串。

#!/usr/bin/python
# -*- coding: utf-8 -*-
12
def java_string_hashcode(s):
    """Mimic Java's hashCode in python 2"""
    try:
        s = unicode(s)
    except:
        try:
            s = unicode(s.decode('utf8'))
        except:
            raise Exception("Please enter a unicode type string or utf8 bytestring.")
    h = 0
    for c in s:
        h = int((((31 * h + ord(c)) ^ 0x80000000) & 0xFFFFFFFF) - 0x80000000)
    return h

在Python 2中,你应该这样做。

问题有两个方面:

  • 你应该使用unicode类型,并确保它确实是这种类型。
  • 在每一步之后,你需要防止Python自动把数据转换成长整型。可以通过位运算来获取正确的整型,以便进行下一步操作。(通过交换符号位、掩码到32位,然后减去符号位的值,如果符号位存在,就会得到一个负数,如果符号位不存在,就会得到一个正数。这种方式模仿了Java中的整型行为。)

另外,正如其他回答所提到的,对于硬编码的非ASCII字符,请将你的源文件保存为utf8格式,并在文件顶部写上:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

确保如果你接收到用户输入,要把它们处理为unicode类型,而不是字符串类型。(在Python 3中这不是问题)

撰写回答