在Javascript / jQuery中從字符串生成一個哈希


Answers

編輯

基於我的jsperf測試,接受的答案實際上更快: http://jsperf.com/hashcodelordvlad ://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);              
}
Question

我需要將字符串轉換為某種形式的散列。 這是可能的JavaScript / jQuery?

我沒有使用服務器端語言,所以我不能這樣做。




通過這個解決方案,我們可以指定字符集以避免在應用程序層之間存儲或發送值時出現一些問題,例如:當結果字符串(哈希)產生百分比編碼並且該字符串從視圖中使用GET方法發送給控制器時層。

function doHashCode() {
    String.prototype.hashCode = function () {
        var text = "";
        var possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        for (var i = 0; i < 15; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        return text;
    }

    var hash = new String().hashCode();
    $('#input-text-hash').val(hash); // your html input text

}



基於ES6中接受的答案 。 更小,可維護,適用於現代瀏覽器。

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));




一個從here改編的快速簡潔的文章:

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}



感謝mar10的例子,我發現了一種在C#和Javascript中為FNV-1a獲得相同結果的方法。 如果存在unicode字符,則為了性能而丟棄較高部分。 不知道為什麼在散列時維護這些元素會有所幫助,因為現在只有散列url路徑。

C#版本

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}

JavaScript版本

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;

    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}



我已經將兩個解決方案(用戶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();



這是一個精緻,性能更好的變體:

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};

這與Java的標準object.hashCode()的實現相匹配。

這裡也是一個只返回肯定hashcode的文件:

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};

這裡有一個匹配的Java,它只返回肯定的hashcode:

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

請享用!