Efficiënt een alfanumerieke tekenreeks van 16 tekens genereren

Ik ben op zoek naar een zeer snelle manier om een ​​alfanumerieke unieke id voor een primaire sleutel in een tabel te genereren.

Zou zoiets werken?

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

Wat zou een goede manier zijn om willekeurige getallen te genereren?
Als ik het baseer op microtime, moet ik rekening houden met de mogelijkheid van meerdere oproepen van genKey() tegelijkertijd vanuit verschillende instanties.

Of is er een betere manier om dit allemaal te doen?


Antwoord 1, autoriteit 100%

Aangezien geen van de antwoorden u een willekeurige reeks geeft die bestaat uit de tekens 0-9, a-z, A-Z: Hier is een werkende oplossing die u een van ongeveer. 62^16 = 4.76724 e+28 toetsen:

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

Het is ook zeer leesbaar zonder ASCII-codes uit het hoofd te kennen.

Er is een nog kortere versie sinds python 3.6.2:

import random, string
x = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
print(x)

Antwoord 2, autoriteit 36%

U kunt dit gebruiken:

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

Er is geen garantie dat de gegenereerde sleutels uniek zijn, dus u moet klaar zijn om het opnieuw te proberen met een nieuwe sleutel in het geval dat de originele invoeging mislukt. Je zou ook kunnen overwegen om een ​​deterministisch algoritme te gebruiken om een ​​string te genereren van een automatisch verhoogd ID in plaats van willekeurige waarden te gebruiken, omdat dit je uniekheid garandeert (maar het geeft ook voorspelbare sleutels).


Antwoord 3, autoriteit 24%

Bekijk de uuid-module(Python 2.5+).

Een snel voorbeeld:

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

Merk op dat het OP om een ​​alfanumerieke reeks van 16 tekens vroeg, maar dat de UUID4-reeksen 32 tekens lang zijn. U moet deze tekenreeks niet afkappen, maar de volledige 32 tekens gebruiken.


Antwoord 4, autoriteit 20%

In Python 3.6, uitgebracht in december 2016, werd de module secretsgeïntroduceerd.

Je kunt nu een willekeurige token op deze manier genereren:

import secrets
secrets.token_hex(16)

Van de Python-documenten:

De module secretswordt gebruikt voor het genereren van cryptografisch sterke
willekeurige getallen geschikt voor het beheren van gegevens zoals wachtwoorden, account
authenticatie, beveiligingstokens en gerelateerde geheimen.

In het bijzonder moeten secretsworden gebruikt in plaats van de standaard
pseudo-willekeurige nummergenerator in de randommodule, die is ontworpen
voor modellering en simulatie, niet voor beveiliging of cryptografie.

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


Antwoord 5, autoriteit 5%

Voor willekeurige getallen is os.urandomeen goede bron:

>> import os
 >> import hashlib
 >> random_data = os.urandom(128)
 >> hashlib.md5(random_data).hexdigest()[:16]

Antwoord 6, autoriteit 2%

>>> import random
>>> ''.join(random.sample(map(chr, range(48, 57) + range(65, 90) + range(97, 122)), 16))
'CDh0geq3NpKtcXfP'

Antwoord 7

Deze waarde wordt bij elke oproep met 1 verhoogd (hij loopt rond). Bepalen waar de waarde het beste kan worden opgeslagen, hangt af van hoe u het gebruikt. Mogelijk vindt u dezeuitleg interessant, omdat bespreekt niet alleen hoe Guids werken, maar ook hoe je een kleinere kunt maken.

Het korte antwoord is dit:
Gebruik sommige van die tekens als een tijdstempel en de andere tekens als een “uniquifier”, een waarde die met 1 wordt verhoogd bij elke aanroep naar uw uid-generator.


Antwoord 8

Er is een officieel recept:

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(16))
print(password)

Hiermee wordt een uitvoer gemaakt die lijkt op 'STCT3jdDUkppph03'.


Antwoord 9

Ik geef de voorkeur aan urandom boven secrets.token_hex, omdat het monsters neemt van een rijkere tekenset en daarom een ​​kleinere lengte nodig heeft om dezelfde entropie te bereiken.

os.urandom, dat leest uit urandom, wordt als veilig beschouwd (zie het relevante antwoord op een vraag als urandom veilig is). U kunt dan zoveel u wilt uit urandom lezen en als volgt een willekeurig alfanummer maken:

import math
import os
def random_alphanumeric(str_len: int) -> str:
  rand_len = 3 * (math.ceil(str_len / 3) + 1)
  return base64.b64encode(os.urandom(rand_len), altchars=b'aA').decode('ascii')[:str_len]

OPMERKING: de bovenstaande functie is niet veilig. Aangezien u een “zeer snelle manier nodig heeft om een ​​alfanumeriek getal te genereren”, levert deze functie prestatie op boven beveiliging, aangezien de frequenties van Aen A(of welke tekens u ook kiest om te vervangen +en /met) worden verhoogd in vergelijking met wat u anders zou geven.

Als je willekeur boven prestaties stelt, kun je zoiets doen als:

def secure_random_alphanumeric(str_len: int) -> str:
  ret = ''
  while len(ret) < str_len:
    rand_len = 3 * (math.ceil((str_len - len(ret)) / 3) + 2)
    ret += base64.b64encode(os.urandom(rand_len)).decode('ascii').replace('+', '').replace('/', '').replace('=', '')
  return ret[:str_len]

Houd er rekening mee dat het koppelen van replacesneller blijkt te zijn dan het achtereenvolgens aanroepen, volgens dit antwoord.

In het bovenstaande wordt +1 ook vervangen door +2 bij het bepalen van rand_lenom het aantal iteraties te verminderen dat nodig is om de gevraagde lengte te bereiken. Je zou zelfs kunnen vervangen door +3 of meer om de kans op een iteratie nog meer te verkleinen, maar dan zou je prestatie verliezen bij de geketende replace-aanroepen.


Antwoord 10

import math
import secrets
def random_alphanum(length: int) -> str:
    if length == 0:
        return ''
    elif length < 0:
        raise ValueError('negative argument not allowed')
    else:
        text = secrets.token_hex(nbytes=math.ceil(length / 2))
        is_length_even = length % 2 == 0
        return text if is_length_even else text[1:]
  • uuid-methode is inefficiënt en beperktomdat uuid slechts 36 tekens retourneert en vervolgens wordt afgekapt.
  • standaard psuedo-willekeurige nummergenerator is niet geschikt voor beveiligings- of cryptografische toepassingen, een standaardmodule voor geheimen is beschikbaar en is ontworpen voor deze toepassingen.

Antwoord 11

Gebruik gewoon de ingebouwde uuid van python:

Als UUID’s in orde zijn voor uw doeleinden, gebruik dan het ingebouwde uuid-pakket.

Eenregelige oplossing:

>>> import uuid
>>> str(uuid.uuid4().get_hex().upper()[0:16])
'40003A9B8C3045CA'

Antwoord 12

gebruik gewoon python ingebouwd uuid:

import uuid
print uuid.uuid4().hex[:16].upper()

Antwoord 13

U zou de keuzefunctie in np.random kunnen gebruiken die het aantal opgegeven tekens kiest uit een lijst met tekens:

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

dit geeft iets als het volgende weer:
591FXwW61F4Q57av

Other episodes