Genera un hash da una stringa in Javascript / jQuery


Answers

MODIFICARE

basato sui miei test jsperf, la risposta accettata è in realtà più veloce: http://jsperf.com/hashcodelordvlad

ORIGINALE

se qualcuno è interessato, ecco una versione migliorata (più veloce), che fallirà sui browser più vecchi che non hanno la funzione di reduce dell'array.

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

Ho bisogno di convertire stringhe in una qualche forma di hash. È possibile in Javascript / jQuery?

Non sto utilizzando un linguaggio lato server, quindi non posso farlo in quel modo.




Se aiuta qualcuno, ho combinato le due risposte principali in una versione tollerante del vecchio browser, che usa la versione veloce se la reduce è disponibile e ricade nella soluzione di esmiralha se non lo è.

/**
 * @see http://.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;
}

L'utilizzo è come:

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



Questa è una variante raffinata e migliore:

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

object.hashCode() all'applicazione Java dello standard object.hashCode()

Ecco anche uno che restituisce solo hashcode positivi:

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

Ed ecco un matching per Java che restituisce solo hashcode positivi:

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

Godere!




Avevo bisogno di una funzione simile (ma diversa) per generare un ID univoco basato sul nome utente e sull'ora corrente. Così:

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

produce:

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 

modifica giugno 2015: per il nuovo codice uso shortid: https://www.npmjs.com/package/shortid




Uno veloce e conciso che è stato adattato da qui :

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



Sono andato per una semplice concatenazione di codici char convertiti in stringhe esadecimali. Questo ha uno scopo relativamente ristretto, ovvero richiede solo una rappresentazione hash di una stringa SHORT (ad esempio titoli, tag) da scambiare con un lato server che per motivi non rilevanti non può facilmente implementare la porta Java hashCode accettata. Ovviamente nessuna applicazione di sicurezza qui.

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

Questo può essere reso più conciso e tollerante per il browser con Underscore. Esempio:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

Suppongo che se volessi stringere stringhe più grandi in modo simile, potresti semplicemente ridurre i codici char ed esagerare la somma risultante piuttosto che concatenare i singoli caratteri insieme:

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

Naturalmente più rischio di collisione con questo metodo, anche se si potrebbe giocare con l'aritmetica nella riduzione, tuttavia si voleva diversificare e allungare l'hash.




Versione leggermente semplificata della risposta di @ esmiralha.

Non sovrascrivo String in questa versione, poiché ciò potrebbe provocare un comportamento indesiderato.

function hashCode(str) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
        hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
    }
    return hash;
}