Come hash una stringa in 8 cifre?


106

C'è comunque che posso hash una stringa casuale in un numero di 8 cifre senza implementare alcun algoritmo da solo?


2
hash ("your string")% 100000000
Theran

2
8 cifre sembrano troppo piccole e potrebbero causare collisioni di hash se si dispone di un numero elevato di record. stackoverflow.com/questions/1303021/...
DhruvPathak

Usa hashlib poiché l'hash ha un altro scopo!
architettonico

2
Qualsiasi numero finito di cifre comporterà collisioni per un numero sufficientemente elevato di elementi hash, ecco perché non dovresti trattarli come chiavi univoche: tende a trasformarsi nel problema del compleanno.
Alex North-Keys

1
Ho scelto "CityHash" per eseguire l'hashing delle stringhe in interi di 19 cifre (interi a 64 bit), sperando che questo porti a meno potenziali collisioni rispetto al suggerimento di Raymond di seguito. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame

Risposte:


155

Sì, puoi utilizzare i moduli hashlib incorporati o la funzione hash incorporata. Quindi, elimina le ultime otto cifre utilizzando le operazioni modulo o le operazioni di suddivisione delle stringhe nella forma intera dell'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
annuncio di servizio pubblico ... questa tecnica non si traduce effettivamente in un valore hash univoco per la stringa; calcola un hash e poi si trasforma in un valore univoco non garantito
twneale

88
annuncio di servizio pubblico ... ad eccezione del caso speciale di hash perfetti su un insieme limitato di valori di input, le funzioni hash non dovrebbero generare valori univoci garantiti.
Raymond Hettinger

5
Hai letto la domanda dell'OP? Lui (o lei) voleva (o aveva bisogno) di 8 cifre decimali. Inoltre, il modo in cui funzionano le tabelle hash consiste nell'hashing in un piccolo spazio di ricerca (la tabella sparsa). Sembra che tu non sappia che le funzioni hash sono comunemente utilizzate e che non ti preoccupi della domanda effettiva che è stata posta.
Raymond Hettinger

17
Ho letto la domanda. Sto semplicemente osservando che nello stesso spazio di input di SHA-1, la tua risposta è astronomicamente più probabile che produca una collisione che no. Almeno un certo grado di unicità è implicitamente richiesto dalla domanda, ma la tua risposta è una funzione hash nello stesso spirito di una che restituisce semplicemente 12345678 per ogni input. Sono stato in grado di generare sperimentalmente una collisione con un minimo di 1000 input utilizzando questo metodo. Per mantenere la stessa probabilità di collisione di SHA-1, dovresti mappare gli SHA-1 non troncati a numeri interi a 8 cifre. Penso che sia degno di un PSA
twneale

20
Attenzione, non è garantito che gli hash forniscano gli stessi risultati su piattaforme e run.
Mr Napik,

94

La risposta di Raymond è ottima per python2 (però, non hai bisogno dell'abs () né delle parentesi intorno a 10 ** 8). Tuttavia, per python3, ci sono importanti avvertenze. Innanzitutto, assicurati di passare una stringa codificata. In questi giorni, nella maggior parte delle circostanze, è probabilmente anche meglio evitare sha-1 e usare invece qualcosa come sha-256. Quindi, l'approccio hashlib sarebbe:

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

Se invece si desidera utilizzare la funzione hash (), l'avvertenza importante è che, a differenza di Python 2.x, in Python 3.x, il risultato di hash () sarà coerente solo all'interno di un processo, non tra le invocazioni di Python. Vedere qui:

$ 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

Ciò significa che viene suggerita la soluzione basata su hash (), che può essere ridotta a:

hash(s) % 10**8

restituirà lo stesso valore solo all'interno di una determinata esecuzione di 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

Quindi, a seconda se questo è importante nella tua applicazione (lo era nella mia), probabilmente vorrai attenersi all'approccio basato su hashlib.


2
Va notato che questa risposta ha un avvertimento molto importante da Python 3.3, per proteggersi dal tar-pitting Python 3.3 e versioni successive utilizzano un seme di hash casuale all'avvio.
Wolph

Se le cifre non sono il tuo requisito principale, potresti anche usare la hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]strega continuerà ad avere collisioni
solitario

Dovrebbero metterlo sulla scatola!
Tomasz

3

Solo per completare la risposta JJC, in python 3.5.3 il comportamento è corretto se usi hashlib in questo modo:

$ 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

Condivido la nostra implementazione nodejs della soluzione implementata da @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));

Stai condividendo una soluzione nodejs in una domanda su Python?
Harabeck

Sì, quando stavamo costruendo il sistema, il backend lo ha elaborato utilizzando python mentre il frontend ha utilizzato node.js. Necessario per assicurarsi che entrambi funzionino perfettamente.
utente 923227
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.