Eu preciso converter seqüências de caracteres para algum tipo de hash. Isso é possível em JavaScript?
Não estou utilizando uma linguagem do lado do servidor, portanto não posso fazer dessa maneira.
javascript
hash
Freesnöw
fonte
fonte
Respostas:
Fonte: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
fonte
hash << 5 - hash
é o mesmo,hash * 31 + char
mas muito mais rápido. É legal porque é muito rápido e o 31 é um primo pequeno. Ganhar ganhar lá.(hash * 31) + char
é idêntica à saída produzida pelo código baseado em turnos((hash<<5)-hash)+char
, mesmo para strings muito longas (eu testei com strings contendo mais de um milhão de caracteres), portanto, não é "inutilizável" em termos de precisão. A complexidade é O (n) para as versões baseada em número e baseada em turnos, portanto, não é "inutilizável" em termos de complexidade.n
, qual é o maiorn
para o qual não posso ter uma colisão?var hashCode = function hashCode (str) {etc...}
? E então usar comohashCode("mystring")
?EDITAR
com base nos meus testes jsperf, a resposta aceita é realmente mais rápida: http://jsperf.com/hashcodelordvlad
ORIGINAL
se alguém estiver interessado, aqui está uma versão melhorada (mais rápida), que falhará em navegadores mais antigos que não possuem a
reduce
função de matriz.versão da função seta de uma linha:
fonte
Em resposta a esta pergunta Qual algoritmo de hash é melhor para exclusividade e velocidade? , Ian Boyd publicou uma análise aprofundada . Em resumo (como eu o interpreto), ele chega à conclusão de que Murmur é o melhor, seguido por FNV-1a.
O algoritmo String.hashCode () de Java que a esmiralha propôs parece ser uma variante do DJB2.
Alguns benchmarks com grandes seqüências de caracteres de entrada aqui: http://jsperf.com/32-bit-hash
Quando sequências curtas de entrada são divididas, o desempenho do sopro cai em relação ao DJ2B e FNV-1a: http://jsperf.com/32- bit-hash / 3
Então, em geral, eu recomendaria murmur3.
Veja aqui uma implementação de JavaScript: https://github.com/garycourt/murmurhash-js
Se as seqüências de entrada forem curtas e o desempenho for mais importante que a qualidade da distribuição, use o DJB2 (conforme proposto pela resposta aceita por esmiralha).
Se a qualidade e o tamanho pequeno do código forem mais importantes que a velocidade, eu uso esta implementação do FNV-1a (com base nesse código ).
Melhore a probabilidade de colisão
Conforme explicado aqui , podemos estender o tamanho do bit de hash usando este truque:
Use-o com cuidado e não espere muito.
fonte
("0000000" + (hval >>> 0).toString(16)).substr(-8);
? Não é o mesmo que(hval >>> 0).toString(16)
?hval
,(hval >>> 0).toString(16)
pode ter menos de 8 caracteres, por isso é preenchido com zeros. Fiquei confuso porque(hval >>> 0).toString(16)
sempre resultou em uma string de exatamente 8 caracteres para mim.Math.imul
função ES6 . Isso por si só faz com que seja um marco de referência e, finalmente, uma escolha melhor que o DJB2 a longo prazo.Com base na resposta aceita no ES6. Menor, sustentável e funciona em navegadores modernos.
EDIT (2019-11-04) :
versão da função seta de uma linha:
fonte
str += ""
antes de hashing a exceção evitarstr.split is not a function
lançada quando não cordas foram passados como parâmetroshash |= 0
para converter para um int de 32 bits. Esta implementação não. Isso é um inseto?Com isso fora do caminho, aqui está algo melhor - cyrb53 , um hash de 53 bits simples, mas de alta qualidade. É bastante rápido, fornece uma distribuição de hash muito boa e possui taxas de colisão significativamente mais baixas em comparação com qualquer hash de 32 bits.
Semelhante aos conhecidos algoritmos MurmurHash / xxHash, ele usa uma combinação de multiplicação e Xorshift para gerar o hash, mas não tão completo. Como resultado, é mais rápido que no JavaScript e significativamente mais simples de implementar.
Atinge avalanche (não estrita), o que basicamente significa que pequenas mudanças na entrada têm grandes mudanças na saída, fazendo com que o hash resultante pareça aleatório:
Você também pode fornecer uma semente para fluxos alternativos da mesma entrada:
Tecnicamente, é um hash de 64 bits (dois hashes não correlacionados de 32 bits em paralelo), mas o JavaScript é limitado a números inteiros de 53 bits. Se necessário, a saída completa de 64 bits ainda pode ser usada alterando a linha de retorno para uma sequência ou matriz hexadecimal.
Esteja ciente de que a construção de cadeias hexadecimais pode diminuir drasticamente o processamento em lote em situações críticas de desempenho.
E apenas por diversão, aqui está um hash mínimo de 32 bits em 89 caracteres com qualidade superior ao FNV ou DJB2:
fonte
ch
inicializado?'imul'
.Se isso ajuda alguém, combinei as duas principais respostas em uma versão mais tolerante ao navegador, que usa a versão rápida, se
reduce
disponível, e volta para a solução da esmiralha, se não estiver.O uso é como:
fonte
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 é uma variante refinada e com melhor desempenho:
Isso corresponde à implementação do padrão do Java
object.hashCode()
Aqui também está um que retorna apenas códigos de hash positivos:
E aqui está um correspondente para Java que retorna apenas códigos de hash positivos:
Aproveitar!
fonte
Estou um pouco surpreso que ninguém tenha falado sobre a nova API SubtleCrypto ainda.
Para obter um hash de uma string, você pode usar o
subtle.digest
método:fonte
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
Não é exatamente de alto desempenho.Graças ao exemplo de mar10, encontrei uma maneira de obter os mesmos resultados em C # AND Javascript para um FNV-1a. Se houver caracteres unicode, a parte superior será descartada por uma questão de desempenho. Não sei por que seria útil mantê-las durante o hash, já que estou apenas fazendo o hash de caminhos de URL por enquanto.
Versão C #
Versão JavaScript
fonte
Math.imul
poderá ser usado para a etapa de multiplicação, o que melhora significativamente o desempenho . O único problema é que ele não funcionará no IE11 sem um calço .Um rápido e conciso que foi adaptado daqui :
fonte
Eu precisava de uma função semelhante (mas diferente) para gerar um ID exclusivo com base no nome de usuário e no horário atual. Assim:
Produz:
editar Jun 2015: Para o novo código, uso shortid: https://www.npmjs.com/package/shortid
fonte
Meu liner rápido (muito longo) baseado no
Multiply+Xor
método da FNV :fonte
SubtleCrypto.digest
Tem certeza de que não pode fazer dessa maneira ?
Você esqueceu que está usando Javascript, a linguagem em constante evolução?
Tente
SubtleCrypto
. Ele suporta funções de hash SHA-1, SHA-128, SHA-256 e SHA-512.fonte
Estou meio atrasado para a festa, mas você pode usar este módulo: crypto :
O resultado dessa função é sempre é a
64
sequência de caracteres; algo assim:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"
fonte
Combinei as duas soluções (usuários esmiralha e lordvlad) para obter uma função que deveria ser mais rápida para navegadores que suportam a função js reduzir () e ainda compatível com navegadores antigos:
Exemplo:
fonte
Se você deseja evitar colisões, pode usar um hash seguro como o SHA-256 . Existem várias implementações JavaScript SHA-256.
Eu escrevi testes para comparar várias implementações de hash, consulte https://github.com/brillout/test-javascript-hash-implementations .
Ou vá para http://brillout.github.io/test-javascript-hash-implementations/ para executar os testes.
fonte
Esse hash deve ser um pouco mais seguro do que algumas outras respostas, mas em uma função, sem nenhuma fonte pré-carregada
Criei basicamente uma versão simplificada e simplificada do sha1.
Você pega os bytes da string e os agrupa em "palavras" de 4 a 32 bits.
Em seguida, estendemos a cada 8 palavras para 40 palavras (para maior impacto no resultado).
Isso vai para a função de hash (a última redução), onde fazemos algumas contas com o estado atual e a entrada. Nós sempre damos 4 palavras.
Esta é quase uma versão de um comando / linha usando map, reduzir ... em vez de loops, mas ainda é muito rápido
também convertemos a saída em hexadecimal para obter uma string em vez de uma matriz de palavras.
O uso é simples. por exemplo
"a string".hash()
, retornará"88a09e8f9cc6f8c71c4497fbb36f84cd"
Mostrar snippet de código
fonte
Eu fui para uma simples concatenação de códigos de caracteres convertidos em seqüências de caracteres hexadecimais. Isso serve a um propósito relativamente restrito, ou seja, apenas a necessidade de uma representação hash de uma string SHORT (por exemplo, títulos, tags) ser trocada com um servidor que, por razões não relevantes, não possa implementar facilmente a porta Java hashCode aceita. Obviamente, nenhum aplicativo de segurança aqui.
Isso pode ser mais conciso e tolerante ao navegador com o Underscore. Exemplo:
Suponho que, se você quisesse hash de seqüências maiores de maneira semelhante, seria possível reduzir os códigos de caracteres e hexificar a soma resultante, em vez de concatenar os caracteres individuais:
Naturalmente, há mais risco de colisão com esse método, embora você possa mexer na aritmética da redução, no entanto, deseja diversificar e aumentar o hash.
fonte
Versão ligeiramente simplificada da resposta de @ esmiralha.
Não substituo String nesta versão, pois isso pode resultar em algum comportamento indesejado.
fonte
Adicionando isso porque ninguém o fez ainda, e isso parece ser solicitado e implementado muito com hashes, mas sempre é feito muito mal ...
Isso requer uma entrada de sequência e um número máximo que você deseja que o hash seja igual e produz um número exclusivo com base na entrada de sequência.
Você pode usar isso para produzir um índice exclusivo em uma matriz de imagens (se desejar retornar um avatar específico para um usuário, escolhido aleatoriamente, mas também com base em seu nome, ele será sempre atribuído a alguém com esse nome )
Você também pode usar isso, é claro, para retornar um índice para uma variedade de cores, como para gerar cores de fundo de avatar exclusivas com base no nome de alguém.
fonte
Não vejo nenhum motivo para usar esse código criptográfico complicado em vez de soluções prontas para o uso, como biblioteca de hash de objetos ou etc. confiar no fornecedor é mais produtivo, economiza tempo e reduz os custos de manutenção.
Basta usar https://github.com/puleos/object-hash
fonte
var crypto = require('crypto');
. Eu acho que adiciona esse código de dependência do fornecedor na versão minificada durante uma compilação.