Wie man einen String in 8 Ziffern hasht?

106

Gibt es überhaupt eine Möglichkeit, eine zufällige Zeichenfolge in eine 8-stellige Zahl umzuwandeln, ohne selbst Algorithmen zu implementieren?

Dorafmon
quelle
2
Hash ("Ihre Zeichenfolge")% 100000000
Theran
2
8-stellig scheint zu klein und kann zu Kollisionen von Hashes führen, wenn Sie eine große Anzahl von Datensätzen haben. stackoverflow.com/questions/1303021/…
DhruvPathak
Verwenden Sie Hashlib, da Hash einen anderen Zweck hat!
Architektonische
2
Jede endliche Anzahl von Ziffern führt zu Kollisionen für eine ausreichend große Anzahl von Hash-Elementen. Deshalb sollten Sie sie nicht als eindeutige Schlüssel behandeln - dies führt häufig zum Geburtstagsproblem.
Alex North-Keys
1
Ich habe "CityHash" gewählt, um Zeichenfolgen auf 19-stellige Ganzzahlen (64-Bit-Ganzzahlen) zu hashen, in der Hoffnung, dass dies zu weniger potenziellen Kollisionen führt als der unten vorgeschlagene Vorschlag von Raymond. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame

Antworten:

153

Ja, Sie können die integrierten Hashlib- Module oder die integrierte Hash- Funktion verwenden. Hacken Sie dann die letzten acht Ziffern mit Modulo-Operationen oder String-Slicing-Operationen für die ganzzahlige Form des Hash ab:

>>> 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
Raymond Hettinger
quelle
26
Ankündigung des öffentlichen Dienstes ... Diese Technik führt nicht zu einem eindeutigen Hashwert für die Zeichenfolge. es berechnet einen Hash und mungt dann in einen nicht garantierten eindeutigen Wert
twneale
88
Ankündigung des öffentlichen Dienstes ... Mit Ausnahme des Sonderfalls perfekter Hashes über einen begrenzten Satz von Eingabewerten sollten Hash-Funktionen keine garantierten eindeutigen Werte generieren.
Raymond Hettinger
5
Haben Sie die Frage des OP gelesen? Er (oder sie) wollte (oder brauchte) 8 Dezimalstellen. Die Art und Weise, wie Hash-Tabellen funktionieren, besteht darin, in einen kleinen Suchraum (die Sparse-Tabelle) zu hashen. Sie scheinen nicht zu wissen, dass Hash-Funktionen häufig verwendet werden, und kümmern sich nicht um die eigentliche Frage, die gestellt wurde.
Raymond Hettinger
17
Ich habe die Frage gelesen. Ich beobachte lediglich, dass Ihre Antwort über denselben Eingaberaum wie SHA-1 astronomisch eher zu einer Kollision führt als nicht. Zumindest ein gewisses Maß an Eindeutigkeit ist implizit für die Frage erforderlich, aber Ihre Antwort ist eine Hash-Funktion im selben Sinne wie eine, die einfach 12345678 für jede Eingabe zurückgibt. Mit dieser Methode konnte ich experimentell eine Kollision mit nur 1000 Eingaben erzeugen. Um die gleiche Kollisionswahrscheinlichkeit wie bei SHA-1 beizubehalten, müssten Sie nicht abgeschnittene SHA-1 auf 8-stellige Ganzzahlen abbilden. Ich denke, das ist eines PSA würdig
twneale
20
Vorsicht, Hash (s) werden nicht garantiert, um plattform- und laufübergreifend dieselben Ergebnisse zu erzielen.
Herr Napik
94

Die Antwort von Raymond ist großartig für python2 (allerdings brauchen Sie weder die abs () noch die parens um 10 ** 8). Für Python3 gibt es jedoch wichtige Einschränkungen. Zunächst müssen Sie sicherstellen, dass Sie eine codierte Zeichenfolge übergeben. In den meisten Fällen ist es heutzutage wahrscheinlich auch besser, sich vor sha-1 zu scheuen und stattdessen so etwas wie sha-256 zu verwenden. Der Hashlib-Ansatz wäre also:

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

Wenn Sie stattdessen die Funktion hash () verwenden möchten, besteht die wichtige Einschränkung darin, dass das Ergebnis von hash () im Gegensatz zu Python 2.x in Python 3.x nur innerhalb eines Prozesses konsistent ist und nicht über Python-Aufrufe hinweg. Siehe hier:

$ 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

Dies bedeutet, dass die auf hash () basierende Lösung vorgeschlagen wird, die auf nur Folgendes gekürzt werden kann:

hash(s) % 10**8

gibt nur den gleichen Wert innerhalb eines bestimmten Skriptlaufs zurück:

#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

Abhängig davon, ob dies in Ihrer Anwendung von Bedeutung ist (in meiner), möchten Sie sich wahrscheinlich an den hashlib-basierten Ansatz halten.

JJC
quelle
2
Es sollte beachtet werden, dass diese Antwort seit Python 3.3 eine sehr wichtige Einschränkung aufweist. Zum Schutz vor Python 3.3 und höher wird beim Start ein zufälliger Hash-Startwert verwendet.
Wolph
Wenn Ziffern nicht Ihre Hauptanforderung sind, können Sie auch hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]Hexen verwenden, die immer noch Kollisionen haben
Lony
Sie sollten das auf die Schachtel legen!
Tomasz
3

Um die JJC-Antwort zu vervollständigen, ist das Verhalten in Python 3.5.3 korrekt, wenn Sie hashlib folgendermaßen verwenden:

$ 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
user8948052
quelle
-3

Ich teile unsere NodeJs-Implementierung der Lösung, wie sie von @Raymond Hettinger implementiert wurde.

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));
Benutzer 923227
quelle
Sie teilen eine NodeJS-Lösung in einer Frage zu Python?
Harabeck
Ja, als wir das System erstellt haben - das Backend hat dies mit Python verarbeitet, während das Frontend node.js verwendet hat. Muss sicherstellen, dass beide nahtlos funktionieren.
Benutzer 923227