從Java腳本中的字符串生成哈希

我須要將字符串轉換爲某種形式的哈希。 這在JavaScript中可行嗎? git

我沒有使用服務器端語言,因此我不能那樣作。 github


#1樓

編輯 算法

根據個人jsperf測試,可接受的答案實際上更快: http ://jsperf.com/hashcodelordvlad npm

原版的 數組

若是有人感興趣,這是一個改進的(更快的)版本,它將在缺乏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。 因此: less

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()

產生: dom

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc

編輯2015年6月:對於新代碼,我使用shortid: https ://www.npmjs.com/package/shortid jsp


#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位哈希,衝突早晚也會發生。

哈希衝突機率能夠計算爲 1-e ^(-k(k-1)/ 2N ,近似爲 k ^ 2 / 2N請參見此處 )。 這可能比直覺暗示的要高:
假設一個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();
相關文章
相關標籤/搜索