Generieren Sie effizient eine alphanumerische Zeichenfolge mit 16 Zeichen

76

Ich suche nach einer sehr schnellen Möglichkeit, eine alphanumerische eindeutige ID für einen Primärschlüssel in einer Tabelle zu generieren.

Würde so etwas funktionieren?

def genKey():
    hash = hashlib.md5(RANDOM_NUMBER).digest().encode("base64")
    alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", hash)
    return alnum_hash[:16]

Was wäre ein guter Weg, um Zufallszahlen zu generieren? Wenn ich es auf Mikrozeit stütze, muss ich die Möglichkeit von mehreren Aufrufen von genKey () gleichzeitig aus verschiedenen Instanzen berücksichtigen.

Oder gibt es einen besseren Weg, dies alles zu tun?

verstricken
quelle

Antworten:

105

Da keine der Antworten eine zufällige Zeichenfolge enthält, die aus den Zeichen 0-9, az, AZ besteht: Hier ist eine funktionierende Lösung, die Ihnen eine von ca. 62 ^ 16 = 4,76724 e + 28 Tasten:

import random, string
x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16))
print(x)

Es ist auch sehr gut lesbar, ohne die ASCII-Codes auswendig zu kennen.

Es gibt eine noch kürzere Version seit python 3.6.2:

import random, string
x = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
print(x)
David Schumann
quelle
1
Die Nummer war eigentlich falsch. Ich habe es aktualisiert. Es wird berechnet, indem die Anzahl der möglichen Zeichen hoch der Länge der Zeichenfolge angegeben wird.
David Schumann
1
Vielen Dank, dass Sie random.choices erwähnt haben. Hatte noch nichts davon gehört und es ist bedeutend schneller als eine Schleife nach Wahl
Andrew
48

Sie können dies verwenden:

>>> import random
>>> ''.join(random.choice('0123456789ABCDEF') for i in range(16))
'E2C6B2E19E4A7777'

Es gibt keine Garantie dafür, dass die generierten Schlüssel eindeutig sind. Sie sollten daher bereit sein, einen neuen Schlüssel erneut zu verwenden, falls die ursprüngliche Einfügung fehlschlägt. Möglicherweise möchten Sie auch einen deterministischen Algorithmus verwenden, um eine Zeichenfolge aus einer automatisch inkrementierten ID zu generieren, anstatt zufällige Werte zu verwenden, da dies Ihnen die Eindeutigkeit garantiert (aber auch vorhersehbare Schlüssel liefert).

Mark Byers
quelle
1
zufällig ist nicht zufällig, sondern laut Dokumentation pseudozufällig. Bitte verwenden Sie stattdessen os.urandom.
Nikola
7
@Prometheus. ist os.urandomnicht pseudo-zufällig?
Aaronasterling
1
Ich antwortete auf Mark Byers lose Verwendung des Begriffs "Zufallswerte". os.urandomist immer noch pseudozufällig, aber kryptografisch sicher pseudozufällig, was es für eine Vielzahl von Anwendungsfällen im Vergleich zu viel besser geeignet macht random.
Nikola
1
@ Nikola Es ist nicht wirklich wichtig, ob die Schlüssel nur pseudozufällig sind, sie werden für die Indizierung verwendet.
Yamm
3
Vielleicht offensichtlich, aber 'deterministisch' bedeutet nicht eindeutig. Sie müssen tatsächlich überprüfen, ob der Algorithmus eine sehr lange Wiederholungsperiode hat. get_key = lambda n: n % 10ist deterministisch, aber nicht lange einzigartig.
Mark
37

Schauen Sie sich das UUID-Modul (Python 2.5+) an.

Ein kurzes Beispiel:

>>> import uuid
>>> uid = uuid.uuid4()
>>> uid.hex
'df008b2e24f947b1b873c94d8a3f2201'

Beachten Sie, dass das OP nach einer 16-stelligen alphanumerischen Zeichenfolge gefragt hat, die UUID4-Zeichenfolgen jedoch 32 Zeichen lang sind. Sie sollten diese Zeichenfolge nicht abschneiden, sondern die vollständigen 32 Zeichen verwenden.

ChristopheD
quelle
7
Dies sind 32 Zeichen, und das Abschneiden von Guids ist unsicher.
Brian
Richtig (über die Kürzung). Auf der anderen Seite: Ich würde nur 32 Zeichen speichern (es sei denn, Sie haben einen ganz bestimmten Grund, nur 16 zu speichern).
ChristopheD
1
@ Brian Hallo, ich muss wissen, warum Guids nicht sicher sind? Hast du eine Referenz?
Adiyat Mubarak
1
@AdiyatMubarak: Grundsätzlich brauchen Sie keine Referenz. Guids werden als einzigartig dokumentiert. Die Hälfte eines Guid ist nicht als eindeutig dokumentiert. Dies vorausgeschickt , blogs.msdn.microsoft.com/oldnewthing/20080627-00/?p=21823 läuft durch das, was passiert , wenn man einen bestimmten GUID - Algorithmus gestutzt.
Brian
19

In Python 3.6, das im Dezember 2016 veröffentlicht wurde, wurde das secretsModul eingeführt.

Sie können jetzt ein zufälliges Token auf folgende Weise generieren:

import secrets

secrets.token_hex(16)

Aus den Python-Dokumenten:

Das secretsModul wird zum Generieren kryptografisch starker Zufallszahlen verwendet, die zum Verwalten von Daten wie Kennwörtern, Kontoauthentifizierung, Sicherheitstoken und verwandten Geheimnissen geeignet sind.

Insbesondere secretssollte bevorzugt der Standard-Pseudozufallszahlengenerator im randomModul verwendet werden, der für die Modellierung und Simulation ausgelegt ist, nicht für Sicherheit oder Kryptographie.

https://docs.python.org/3/library/secrets.html

Brachamul
quelle
6

Für Zufallszahlen ist eine gute Quelle os.urandom:

 >> import os
 >> import hashlib
 >> random_data = os.urandom(128)
 >> hashlib.md5(random_data).hexdigest()[:16]
rlotun
quelle
Ich habe die so großartige Urandom-Funktion vergessen: V und das ist schön, besser als Zeichensätze in einen String einzufügen und dann zu schleifen. Builtin;)
m3nda
Dies wurde auch in anderen Antworten erwähnt. Sie sollten den MD5-Hash nicht abschneiden.
Bman
@bman: Mir ist bewusst, dass es ernsthafte Probleme beim Abschneiden von Vertan-UUIDs gibt, da die Zufälligkeit nicht linear verteilt ist. vor MD5 sollte dies kein Problem sein.
Max
3
>>> import random
>>> ''.join(random.sample(map(chr, range(48, 57) + range(65, 90) + range(97, 122)), 16))
'CDh0geq3NpKtcXfP'
Jan Matějka
quelle
4
Ihre Lösung würde die Zeichen 9, Z und z weglassen. Außerdem wählt sample () jedes Zeichen nur einmal aus. Es würde Ihnen also viel weniger Permutationen geben. Dies würde Ihnen eine Folge von 16 zufälligen Ziffern und Groß- / Kleinbuchstaben geben:''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(6666))
David Schumann
2

Dieser Wert wird bei jedem Aufruf um 1 erhöht (er wird umbrochen). Die Entscheidung, wo der Wert am besten gespeichert werden soll, hängt davon ab, wie Sie ihn verwenden. Diese Erklärung ist möglicherweise von Interesse, da hier nicht nur die Funktionsweise von Guids, sondern auch die Erstellung einer kleineren erläutert wird.

Die kurze Antwort lautet wie folgt: Verwenden Sie einige dieser Zeichen als Zeitstempel und die anderen Zeichen als "Eindeutigkeit". Bei jedem Aufruf Ihres UID-Generators wird der Wert um 1 erhöht.

Brian
quelle
-2

Verwenden Sie einfach Python Builtin UUID:

Wenn UUIDs für Ihre Zwecke in Ordnung sind, verwenden Sie das integrierte UUID- Paket.

Einzeilige Lösung:

>>> import uuid
>>> str(uuid.uuid4().get_hex().upper()[0:16])
'40003A9B8C3045CA'
Jay Patel
quelle
6
Die UUID hat eine Länge von 32 Zeichen. Wenn Sie nur Zeichen von 0 bis 15 verwenden, erhalten Sie Duplikate.
Diaa Mohamed Kasem
-2

einfach verwenden Python eingebaute uuid :

import uuid
print uuid.uuid4().hex[:16].upper()
Chirag Maliwal
quelle
-3

Sie können die Auswahlfunktion in np.random verwenden, mit der die Anzahl der angegebenen Zeichen aus einer Liste von Zeichen ausgewählt wird:

import numpy as np
chars = np.array(list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'))
np_codes = np.random.choice(chars,16)
print(''.join([val for val in np_codes]))

Dies gibt ungefähr Folgendes aus: 591FXwW61F4Q57av

Praveen Kumar Sridhar
quelle