Générer un hachage à partir d'une chaîne dans Javascript / jQuery


Answers

MODIFIER

basé sur mes tests jsperf, la réponse acceptée est en fait plus rapide: http://jsperf.com/hashcodelordvlad

ORIGINAL

Si quelqu'un est intéressé, voici une version améliorée (plus rapide), qui échouera sur les anciens navigateurs qui n'ont pas la fonction de reduce matrice.

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

J'ai besoin de convertir les chaînes en une forme de hachage. Est-ce possible en Javascript / jQuery?

Je n'utilise pas de langage côté serveur, donc je ne peux pas le faire de cette façon.




C'est une variante raffinée et performante:

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;
};

Cela correspond à l'implémentation Java de l'objet standard object.hashCode()

Voici aussi celui qui ne renvoie que des hashcodes positifs:

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

Et voici un correspondant pour Java qui ne renvoie que des hashcodes positifs:

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

Prendre plaisir!




Grâce à l'exemple de mar10, j'ai trouvé un moyen d'obtenir les mêmes résultats en C # ET Javascript pour un FNV-1a. Si des caractères Unicode sont présents, la partie supérieure est mise au rebut pour des raisons de performance. Je ne sais pas pourquoi il serait utile de les maintenir en hachage, car je ne fais que hacher les chemins d'URL pour le moment.

Version 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());
}

Version 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);
}



J'ai combiné les deux solutions (utilisateurs esmiralha et lordvlad) pour obtenir une fonction qui devrait être plus rapide pour les navigateurs qui supportent la fonction js reduce () et qui sont toujours compatibles avec les anciens navigateurs:

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;
    }
};

Exemple:

my_string = 'xyz';
my_string.hashCode();






Un rapide et concis qui a été adapté d' here :

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



Basé sur la réponse acceptée dans ES6. Plus petit, maintenable et fonctionne dans les navigateurs modernes.

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

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




Avec cette solution, nous pouvons spécifier le jeu de caractères pour éviter certains problèmes lorsque les valeurs sont stockées ou envoyées entre couches d'application, par exemple: Lorsque la chaîne de résultat (hash) produit un codage en pourcentage et que cette chaîne est envoyée au contrôleur utilisant la méthode GET couche.

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

}