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.
javascript
hash
Freesnöw
fuente
fuente
Respuestas:
Fuente: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
fuente
hash << 5 - hash
es el mismohash * 31 + char
pero MUCHO más rápido. Es bueno porque es muy rápido, y 31 es un primo pequeño. Gana gana allí.(hash * 31) + char
es idéntica a la salida producida por el código basado en turnos((hash<<5)-hash)+char
, incluso para cadenas muy largas (lo he probado con cadenas que contienen más de un millón de caracteres), por lo que no es "inutilizable" en términos de precisión La complejidad es O (n) para las versiones basadas en números y en turnos, por lo que no es "inutilizable" en términos de complejidad.n
, ¿cuál es el más granden
para el cual no puedo tener una colisión?var hashCode = function hashCode (str) {etc...}
? Y luego usar comohashCode("mystring")
?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
reduce
función de matriz.versión de función de flecha de una línea:
fuente
En una respuesta a esta pregunta, ¿qué algoritmo de hash es mejor para la unicidad y la velocidad? Ian Boyd publicó un buen análisis en profundidad . En resumen (según 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.
Algunos puntos de referencia con cadenas de entrada grandes aquí: http://jsperf.com/32-bit-hash
Cuando se cortan cadenas de entrada cortas , el rendimiento del murmullo disminuye, en relación con DJ2B y FNV-1a: http://jsperf.com/32- bit-hash / 3
Entonces, 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 distribución, use DJB2 (como lo propone la respuesta aceptada por esmiralha).
Si la calidad y el tamaño de código pequeño son más importantes que la velocidad, utilizo esta implementación de FNV-1a (basada en este código ).
Mejora la probabilidad de colisión
Como se explica aquí , podemos extender el tamaño de bit hash usando este truco:
Úselo con cuidado y no espere demasiado.
fuente
("0000000" + (hval >>> 0).toString(16)).substr(-8);
? ¿No es lo mismo que(hval >>> 0).toString(16)
?hval
,(hval >>> 0).toString(16)
puede tener menos de 8 caracteres, por lo que debe rellenarlo con ceros. Estaba confundido porque(hval >>> 0).toString(16)
siempre resultó en una cadena de 8 caracteres exactamente para mí.Math.imul
función ES6 . Eso solo lo convierte en los principales puntos de referencia y, en última instancia, una mejor opción que DJB2 a largo plazo.Basado en la respuesta aceptada en ES6. Más pequeño, mantenible y funciona en navegadores modernos.
EDITAR (2019-11-04) :
versión de función de flecha de una línea:
fuente
str += ""
antes del hash para evitar que sestr.split is not a function
hash |= 0
para convertir a un int de 32 bits. Esta implementación no lo hace. ¿Es esto un error?Con eso fuera del camino, aquí hay algo mejor: cyrb53 , un hash de 53 bits simple pero de alta calidad. Es bastante rápido, proporciona una muy buena distribución de hash y tiene tasas de colisión significativamente más bajas en comparación con cualquier hash de 32 bits.
Similar a los conocidos algoritmos MurmurHash / xxHash, utiliza una combinación de multiplicación y Xorshift para generar el hash, pero no tan exhaustivo. Como resultado, es más rápido que en JavaScript y significativamente más simple de implementar.
Alcanza una avalancha (no estricta), lo que básicamente significa que pequeños cambios en la entrada tienen grandes cambios en la salida, haciendo que el hash resultante parezca aleatorio:
También puede suministrar una semilla para secuencias alternativas de la misma entrada:
Técnicamente es un hash de 64 bits (dos hashes de 32 bits no correlacionados en paralelo), pero JavaScript está limitado a enteros de 53 bits. Si es necesario, la salida completa de 64 bits todavía se puede usar alterando la línea de retorno para una cadena o matriz hexadecimal.
Tenga en cuenta que la construcción de cadenas hexadecimales puede ralentizar drásticamente el procesamiento por lotes en situaciones críticas de rendimiento.
Y solo por diversión, aquí hay un hash mínimo de 32 bits en 89 caracteres con mayor calidad que incluso FNV o DJB2:
fuente
ch
inicializa?'imul'
.Si ayuda a alguien, combiné las dos respuestas principales en una versión más antigua tolerante al navegador, que usa la versión rápida si
reduce
está disponible y recurre a la solución de esmiralha si no es así.El uso es como:
fuente
String.prototype.hashCode = function(){ var hash = 5381; if (this.length === 0) return hash; for (var i = 0; i < this.length; i++) { var character = this.charCodeAt(i); hash = ((hash<<5)+hash)^character; // Convert to 32bit integer } return hash; }
Esta es una variante refinada y de mejor rendimiento:
Esto coincide con la implementación de Java del estándar
object.hashCode()
Aquí también hay uno que devuelve solo códigos hash positivos:
Y aquí hay una coincidencia para Java que solo devuelve códigos hash positivos:
¡Disfrutar!
fuente
Estoy un poco sorprendido de que nadie haya hablado aún sobre la nueva API SubtleCrypto .
Para obtener un hash de una cadena, puede usar el
subtle.digest
método:fuente
var promise = crypto.subtle.digest({name: "SHA-256"}, Uint8Array.from(data)); promise.then(function(result){ console.log(Array.prototype.map.call(new Uint8Array(result), x => x.toString(16).padStart(2, '0')).join('')); });
crypto
no es exactamente eficiente.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, la porción superior se descarta por el bien del rendimiento. No sé por qué sería útil mantenerlos cuando se realiza el hashing, ya que solo estoy haciendo hashing en las rutas de URL por ahora.
Versión C #
Versión JavaScript
fuente
Math.imul
puede usarse para el paso de multiplicación, lo que mejora enormemente el rendimiento . El único problema es que no funcionará en IE11 sin una cuña .Una rápida y concisa que fue adaptada desde aquí :
fuente
Necesitaba una función similar (pero diferente) para generar una identificación única basada en el nombre de usuario y la hora actual. Entonces:
Produce:
editar junio de 2015: para el nuevo código uso shortid: https://www.npmjs.com/package/shortid
fuente
Mi revestimiento rápido (muy largo) basado en el
Multiply+Xor
método de FNV :fuente
SubtleCrypto.digest
¿Estás seguro de que no puedes hacerlo de esa manera ?
¿Olvidaste que estás usando Javascript, el lenguaje en constante evolución?
Tratar
SubtleCrypto
. Es compatible con las funciones hash SHA-1, SHA-128, SHA-256 y SHA-512.fuente
Llego un poco tarde a la fiesta, pero puedes usar este módulo: crypto :
El resultado de esta función es siempre una
64
cadena de caracteres; algo como esto:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"
fuente
He combinado las dos soluciones (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:
Ejemplo:
fuente
Si desea evitar colisiones, puede usar un hash seguro como SHA-256 . Hay varias implementaciones de JavaScript SHA-256.
Escribí pruebas para comparar varias implementaciones de hash, consulte https://github.com/brillout/test-javascript-hash-implementations .
O vaya a http://brillout.github.io/test-javascript-hash-implementations/ , para ejecutar las pruebas.
fuente
Esto debería ser un hash un poco más seguro que algunas otras respuestas, pero en una función, sin ninguna fuente precargada
Básicamente, creé una versión simplificada simplificada de sha1.
Toma los bytes de la cadena y los agrupa por "palabras" de 4 a 32 bits.
Luego, ampliamos cada 8 palabras a 40 palabras (para un mayor impacto en el resultado).
Esto va a la función hash (la última reducción) donde hacemos algunos cálculos con el estado actual y la entrada. Siempre sacamos 4 palabras.
Esta es casi una versión de un comando / una línea usando map, reduce ... en lugar de bucles, pero sigue siendo bastante rápido
También convertimos la salida a hexadecimal para obtener una cadena en lugar de una matriz de palabras.
El uso es simple. para expandir
"a string".hash()
regresará"88a09e8f9cc6f8c71c4497fbb36f84cd"
Mostrar fragmento de código
fuente
Fui por una simple concatenación de códigos char convertidos en cadenas hexadecimales. Esto tiene un propósito relativamente limitado, es decir, solo necesita una representación hash de una cadena CORTA (por ejemplo, títulos, etiquetas) para intercambiar con un lado del servidor que por razones no relevantes no puede implementar fácilmente el puerto Java hashCode aceptado. Obviamente no hay aplicación de seguridad aquí.
Esto se puede hacer más conciso y tolerante al navegador con Underscore. Ejemplo:
Supongo que si quisieras cortar cadenas más grandes de manera similar, podrías reducir los códigos de caracteres y hexadecimal la suma resultante en lugar de concatenar los caracteres individuales:
Naturalmente, existe un mayor riesgo de colisión con este método, aunque podría jugar con la aritmética en la reducción, sin embargo, quería diversificar y alargar el hash.
fuente
Versión ligeramente simplificada de la respuesta de @esmiralha.
No anulo String en esta versión, ya que eso podría provocar un comportamiento no deseado.
fuente
Agregando esto porque nadie lo hizo todavía, y parece que se ha pedido e implementado mucho con hashes, pero siempre se hizo muy mal ...
Esto toma una entrada de cadena y un número máximo que desea que iguale el hash, y produce un número único basado en la entrada de cadena.
Puede usar esto para producir un índice único en una matriz de imágenes (si desea devolver un avatar específico para un usuario, elegido al azar, pero también elegido en función de su nombre, por lo que siempre se asignará a alguien con ese nombre )
También puede usar esto, por supuesto, para devolver un índice en una matriz de colores, como para generar colores de fondo de avatar únicos basados en el nombre de alguien.
fuente
No veo ninguna razón para usar este código criptográfico demasiado complicado en lugar de soluciones listas para usar, como la biblioteca de hash de objetos, etc. Confiar en el proveedor es más productivo, ahorra tiempo y reduce los costos de mantenimiento.
Simplemente use https://github.com/puleos/object-hash
fuente
var crypto = require('crypto');
. Creo que agrega este código de dependencia del proveedor en la versión minimizada durante una compilación.