tables lista etiquetas caracter cadena buscar javascript hash

lista - Generar un hash de cadena en Javascript



javascript hash string (18)

Aquí hay un hash de 53 bits simple y bien distribuido. Es bastante rápido y tiene bajas tasas de colisión.

var cyrb53 = function(str) { var p1 = 2654435761, p2 = 1597334677, h1 = 0xdeadbeef | 0, h2 = 0x41c6ce57 | 0; for (var i = 0; i < str.length; i++) ch = str.charCodeAt(i), h1 = Math.imul(h1 + ch, p1), h2 = Math.imul(h2 + ch, p2); h1 = Math.imul(h1 ^ h1 >>> 16, p2), h2 = Math.imul(h2 ^ h2 >>> 15, p1); return (h2 & 2097151) * 4294967296 + h1; };

Logra una avalancha (no estricta), por lo que los cambios pequeños tienen grandes cambios en la salida, lo que hace que parezca aleatorio

0xe00c44e568f86 = "a" 0x893099dbedf04 = "b" 0x98f3f59367810 = "revenge" 0x45f880d099bbf = "revenue"

53 bits es el límite de enteros JS y tiene una probabilidad de colisión significativamente menor que los hashes de 32 bits. Pero si 53 bits no son suficientes para usted, aún puede usar los 64 bits construyendo una cadena o matriz hex:

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0); // or return [h2>>>0, h1>>>0];

El problema es que la construcción de la cadena hexadecimal se convierte en el cuello de botella en el rendimiento, y la matriz necesita dos operadores de comparación en lugar de uno, lo que no es tan conveniente.

Necesito convertir cadenas a alguna forma de hash. ¿Es esto posible en JavaScript?

No estoy utilizando un lenguaje del lado del servidor, así que no puedo hacerlo de esa manera.


Basado en respuesta aceptada en ES6. Más pequeño, mantenible y funciona en navegadores modernos.

function hashCode(str) { return str.split('''').reduce((prevHash, currVal) => (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0); } // Test console.log("hashCode(/"Hello!/"): ", hashCode(''Hello!''));


Con esta solución, podemos especificar el conjunto de caracteres para evitar algunos problemas cuando los valores se almacenan o envían entre capas de aplicaciones, por ejemplo: cuando la cadena de resultados (hash) produce un porcentaje de codificación y esa cadena se envía al controlador utilizando el método GET desde la vista capa.

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 }


Esta es una variante refinada y de mejor rendimiento:

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

Esto coincide con la implementación de Java del object.hashCode() estándar object.hashCode()

Aquí también hay uno que devuelve solo códigos hash positivos:

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

Y aquí hay una coincidencia para Java que solo devuelve códigos hash positivos:

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

¡Disfrutar!


Estoy un poco sorprendido de que nadie haya hablado de la nueva API de SubtleCrypto todavía.

Para obtener un hash de una cadena, puede usar el método subtle.digest :

function getHash(str, algo = "SHA-256") { let strBuf = new TextEncoder(''utf-8'').encode(str); return crypto.subtle.digest(algo, strBuf) .then(hash => { window.hash = hash; // here hash is an arrayBuffer, // so we''ll connvert it to its hex version let result = ''''; const view = new DataView(hash); for (let i = 0; i < hash.byteLength; i += 4) { result += (''00000000'' + view.getUint32(i).toString(16)).slice(-8); } return result; }); } getHash(''hello world'') .then(hash => { console.log(hash); });


Fui por una simple concatenación de códigos de caracteres convertidos en cadenas hexadecimales. Esto tiene un propósito relativamente limitado, es decir, solo necesita una representación de hash de una cadena SHORT (por ejemplo, títulos, etiquetas) para intercambiarla con un servidor que, por razones no relevantes, no puede implementar fácilmente el puerto Java de hashCode aceptado. Obviamente no hay aplicación de seguridad aquí.

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

Esto se puede hacer más conciso y tolerante al navegador con el guión bajo. Ejemplo:

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

Supongo que si desearahear cadenas más grandes de manera similar, simplemente podría reducir los códigos de caracteres y hexadecir la suma resultante en lugar de concatenar los caracteres individuales juntos:

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, existe un mayor riesgo de colisión con este método, aunque usted podría jugar con la aritmética en la reducción, aunque quisiera diversificar y alargar el hash.


Gracias al ejemplo de mar10, encontré una manera de obtener los mismos resultados en C # Y Javascript para un FNV-1a. Si hay caracteres Unicode presentes, la parte superior se descarta por motivos de rendimiento. No sé por qué sería útil mantenerlos al hacer hash, ya que por el momento solo soy hash de las rutas URL.

Versión 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()); }

Versión de 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); }


He combinado las dos soluciones (los usuarios esmiralha y lordvlad) para obtener una función que debería ser más rápida para los navegadores que admiten la función js reduce () y aún compatible con los navegadores antiguos:

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

Ejemplo:

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


Llego tarde a la fiesta, pero puedes usar este módulo: crypto :

const crypto = require(''crypto''); const SALT = ''$ome$alt''; function generateHash(pass) { return crypto.createHmac(''sha256'', SALT) .update(pass) .digest(''hex''); }

El resultado de esta función es siempre la cadena de 64 caracteres; algo como esto: "aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"


Mi rápida (muy larga) una línea basada en el método Multiply+Xor FNV:

my_string.split('''').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);


Necesitaba una función similar (pero diferente) para generar una identificación única basada en el nombre de usuario y la hora actual. Asi que:

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

edición de junio de 2015: para el nuevo código que uso shortid: https://www.npmjs.com/package/shortid


Si ayuda a alguien, combiné las dos respuestas principales en una versión anterior con tolerancia al navegador, que usa la versión rápida si está disponible la reduce y vuelve a la solución de esmiralha si no lo está.

/** * @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; }

El uso es como

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



Una rápida y concisa que fue adaptada desde here :

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


Versión ligeramente simplificada de la respuesta de @esmiralha.

No anulo la Cadena en esta versión, ya que eso podría resultar en un comportamiento no deseado.

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


EDITAR

basado en mis pruebas jsperf, la respuesta aceptada es en realidad más rápida: http://jsperf.com/hashcodelordvlad

ORIGINAL

Si alguien está interesado, aquí hay una versión mejorada (más rápida), que fallará en los navegadores más antiguos que carecen de la función de reduce matriz.

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


Nota: Incluso con el mejor hash de 32 bits, tendrá que lidiar con el hecho de que las colisiones se producirán tarde o temprano. Es decir, dos cadenas de entrada diferentes devolverán el mismo valor hash con una probabilidad de al menos 1: 2 ^ 32.

En respuesta a esta pregunta, ¿qué algoritmo de hash es mejor para la singularidad y la velocidad? , Ian Boyd publicó un buen análisis en profundidad . En resumen (como lo interpreto), llega a la conclusión de que Murmur es el mejor, seguido de FNV-1a.
El algoritmo String.hashCode () de Java que esmiralha propuso parece ser una variante de DJB2.

  • FNV-1a tiene una mejor distribución que DJB2, pero es más lento
  • DJB2 es más rápido que FNV-1a, pero tiende a producir más colisiones
  • MurmurHash3 es mejor y más rápido que DJB2 y FNV-1a (pero la implementación optimizada requiere más líneas de código que FNV y DJB2)

Algunos puntos de referencia con cadenas de entrada grandes aquí: http://jsperf.com/32-bit-hash
Cuando las cadenas de entrada cortas están en hash, el rendimiento del murmullo disminuye en relación con DJ2B y FNV-1a: http://jsperf.com/32-bit-hash/3

Así que en general recomendaría murmur3.
Vea aquí para una implementación de JavaScript: https://github.com/garycourt/murmurhash-js

Si las cadenas de entrada son cortas y el rendimiento es más importante que la calidad de la distribución, use DJB2 (según lo propuesto por la respuesta aceptada por esmiralha).

Si la calidad y el pequeño tamaño del código son más importantes que la velocidad, uso esta implementación de FNV-1a (basada en este código ).

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