从Java脚本中的字符串生成哈希

六眼飞鱼酱① 提交于 2020-02-26 00:28:26

我需要将字符串转换为某种形式的哈希。 这在JavaScript中可行吗?

我没有使用服务器端语言,所以我不能那样做。


#1楼

编辑

根据我的jsperf测试,可接受的答案实际上更快: http ://jsperf.com/hashcodelordvlad

原版的

如果有人感兴趣,这是一个改进的(更快的)版本,它将在缺少reduce数组功能的旧版浏览器上失败。

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}

单线箭头功能版本:

hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)

#2楼

我需要一个类似的函数(但有所不同)来根据用户名和当前时间生成一个唯一的ID。 所以:

window.newId = ->
  # create a number based on the username
  unless window.userNumber?
    window.userNumber = 0
  for c,i in window.MyNamespace.userName
    char = window.MyNamespace.userName.charCodeAt(i)
    window.MyNamespace.userNumber+=char
  ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()

产生:

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 

编辑2015年6月:对于新代码,我使用shortid: https ://www.npmjs.com/package/shortid


#3楼

如果对任何人都有用,我会将前两个答案组合成一个较旧的浏览器容忍版本,如果可以使用reduce ,则使用快速版本;如果没有,则使用esmiralha的解决方案。

/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @return {number}
 */
String.prototype.hashCode = function(){
    if (Array.prototype.reduce){
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
    } 
    var hash = 0;
    if (this.length === 0) return hash;
    for (var i = 0; i < this.length; i++) {
        var character  = this.charCodeAt(i);
        hash  = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

用法就像:

var hash = new String("some string to be hashed").hashCode();

#4楼

注意:即使使用最佳的32位哈希,冲突迟早也会发生。

哈希冲突概率可以计算为

,近似为

请参见此处 )。 这可能比直觉暗示的要高:
假设一个32位哈希且k = 10,000个项目,则发生碰撞的概率为1.2%。 对于77,163个样本,概率变为50%! ( 计算器 )。
我建议在底部的一种解决方法。

在回答这个问题时, 哪种哈希算法最适合唯一性和速度? ,伊恩·博伊德(Ian Boyd)进行了深入的分析 。 简而言之(据我的解释),他得出的结论是Murmur最好,其次是FNV-1a。
esmiralha提出的Java String.hashCode()算法似乎是DJB2的一种变体。

  • FNV-1a比DJB2具有更好的分布,但速度较慢
  • DJB2比FNV-1a快,但往往会产生更多碰撞
  • MurmurHash3比DJB2和FNV-1a更好和更快(但是优化的实现比FNV和DJB2需要更多的代码行)

一些带有较大输入字符串的基准测试: http : //jsperf.com/32-bit-hash
散列输入字符串时,相对于DJ2B和FNV-1a,杂音的性能下降: http ://jsperf.com/32-bit-hash/3

因此,一般而言,我会推荐murmur3。
参见此处以获取JavaScript实现: https//github.com/garycourt/murmurhash-js

如果输入字符串短并且性能比分发质量更重要,请使用DJB2(由esmiralha接受的答案提出)。

如果质量和小的代码大小比速度更重要,那么我将使用FNV-1a的此实现(基于此代码 )。

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

提高碰撞概率

如此处所述 ,我们可以使用以下技巧扩展哈希位大小:

function hash64(str) {
    var h1 = hash32(str);  // returns 32 bit (as 8 byte hex string)
    return h1 + hash32(h1 + str);  // 64 bit (as 16 byte hex string)
}

请谨慎使用,但不要期望过高。


#5楼

我结合了两种解决方案(用户esmiralha和lordvlad)来获得一个函数,该函数对于支持js函数reduce()并仍与旧浏览器兼容的浏览器应该更快:

String.prototype.hashCode = function() {

    if (Array.prototype.reduce) {
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);   
    } else {

        var hash = 0, i, chr, len;
        if (this.length == 0) return hash;
        for (i = 0, len = this.length; i < len; i++) {
        chr   = this.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
        }
        return hash;
    }
};

例:

my_string = 'xyz';
my_string.hashCode();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!