Como hash uma string em 8 dígitos?


106

Existe alguma maneira que eu possa hash uma string aleatória em um número de 8 dígitos sem implementar nenhum algoritmo sozinho?


2
hash ("sua string")% 100000000
Theran

2
8 dígitos parecem pequenos e podem resultar em colisões de hashes se você tiver um grande número de registros. stackoverflow.com/questions/1303021/…
DhruvPathak de

Use hashlib, pois o hash tem outro propósito!
arquitetônico de

2
Qualquer número finito de dígitos resultará em colisões para números suficientemente grandes de itens hash, é por isso que você não deve tratá-los como chaves exclusivas - isso tende a se transformar no problema de aniversário.
Alex North-Keys de

1
Eu escolhi "CityHash" para sequências de hash para inteiros de 19 dígitos (inteiros de 64 bits), esperando que isso leve a menos colisões potenciais do que a sugestão de Raymond abaixo. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame

Respostas:


155

Sim, você pode usar os módulos hashlib embutidos ou a função hash embutida. Em seguida, corte os últimos oito dígitos usando operações de módulo ou operações de corte de string na forma inteira do hash:

>>> s = 'she sells sea shells by the sea shore'

>>> # Use hashlib
>>> import hashlib
>>> int(hashlib.sha1(s).hexdigest(), 16) % (10 ** 8)
58097614L

>>> # Use hash()
>>> abs(hash(s)) % (10 ** 8)
82148974

26
anúncio de serviço público ... essa técnica não resulta em um valor hash exclusivo para a string; ele calcula um hash e, em seguida, transforma em um valor único não garantido
twneale

88
anúncio de serviço público ... exceto no caso especial de hashes perfeitos sobre um conjunto limitado de valores de entrada, as funções de hash não devem gerar valores únicos garantidos.
Raymond Hettinger

5
Você leu a pergunta do OP? Ele (ou ela) queria (ou precisava) 8 casas decimais. Além disso, a maneira como as tabelas de hash funcionam é fazer o hash em um pequeno espaço de pesquisa (a tabela esparsa). Você parece não saber que as funções hash desejadas são comumente usadas e não se importa com a pergunta real que foi feita.
Raymond Hettinger

17
Eu li a pergunta. Estou simplesmente observando que, no mesmo espaço de entrada do SHA-1, sua resposta é astronomicamente mais provável de produzir uma colisão do que não. Pelo menos algum grau de exclusividade é implicitamente exigido pela pergunta, mas sua resposta é uma função hash com o mesmo espírito de uma que simplesmente retorna 12345678 para cada entrada. Consegui gerar experimentalmente uma colisão com apenas 1000 entradas usando esse método. Para preservar a mesma probabilidade de colisão do SHA-1, você teria que mapear SHA-1 não truncados para inteiros de 8 dígitos. Eu acho que é digno de um PSA
twneale

20
Cuidado, hash (s) não tem garantia de dar os mesmos resultados em todas as plataformas e execuções.
Sr. Napik

94

A resposta de Raymond é ótima para python2 (embora você não precise do abs () nem dos parênteses em torno de 10 ** 8). No entanto, para python3, existem ressalvas importantes. Primeiro, você precisa se certificar de que está passando uma string codificada. Hoje em dia, na maioria das circunstâncias, provavelmente também é melhor fugir do sha-1 e usar algo como o sha-256. Portanto, a abordagem hashlib seria:

>>> import hashlib
>>> s = 'your string'
>>> int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16) % 10**8
80262417

Se você quiser usar a função hash (), a ressalva importante é que, ao contrário do Python 2.x, no Python 3.x, o resultado de hash () só será consistente dentro de um processo, não entre invocações de python. Veja aqui:

$ python -V
Python 2.7.5
$ python -c 'print(hash("foo"))'
-4177197833195190597
$ python -c 'print(hash("foo"))'
-4177197833195190597

$ python3 -V
Python 3.4.2
$ python3 -c 'print(hash("foo"))'
5790391865899772265
$ python3 -c 'print(hash("foo"))'
-8152690834165248934

Isso significa que a solução baseada em hash () sugerida, que pode ser encurtada para apenas:

hash(s) % 10**8

retornará apenas o mesmo valor em uma determinada execução de script:

#Python 2:
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543

#Python 3:
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
12954124
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
32065451

Portanto, dependendo se isso é importante no seu aplicativo (foi no meu), você provavelmente vai querer manter a abordagem baseada em hashlib.


2
Deve-se notar que esta resposta tem uma advertência muito importante desde o Python 3.3, para proteger contra tar-pitting o Python 3.3 e superior, use uma semente de hash aleatória na inicialização.
Wolph

Se os dígitos não forem seu requisito principal, você também pode usar, mas hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]ainda assim haverá colisões
lony

Eles deveriam colocar isso na caixa!
Tomasz

3

Apenas para completar a resposta JJC, no python 3.5.3 o comportamento está correto se você usar hashlib desta forma:

$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded
$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded

$ python3 -V
Python 3.5.3

-3

Estou compartilhando nossa implementação nodejs da solução implementada por @Raymond Hettinger.

var crypto = require('crypto');
var s = 'she sells sea shells by the sea shore';
console.log(BigInt('0x' + crypto.createHash('sha1').update(s).digest('hex'))%(10n ** 8n));

Você está compartilhando uma solução nodejs em uma pergunta sobre python?
Harabeck

Sim, quando estávamos construindo o sistema - o back-end processou isso usando python enquanto o front-end usava node.js. Necessário para garantir que ambos funcionem perfeitamente.
usuário 923227
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.