[Python] توليد سلسلة عشوائية بأحرف كبيرة وأرقام في بايثون


Answers

يعتبر هذا Quackion Stack Overflow أعلى نتيجة Google الحالية لـ "Python string string". الإجابة الأعلى الحالية هي:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

هذه طريقة ممتازة ، لكن PRNG في عشوائي ليس آمنًا بشكل مشفّر. أفترض أن العديد من الأشخاص الذين يبحثون عن هذا السؤال يريدون إنشاء سلاسل عشوائية للتشفير أو كلمات المرور. يمكنك القيام بذلك بشكل آمن عن طريق إجراء تغيير بسيط في الكود أعلاه:

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

استخدام random.SystemRandom() بدلاً من استخدامات عشوائية / dev / urandom على أجهزة * nix و CryptGenRandom() في Windows. هذه هي PRNGs آمنة التشفير. باستخدام random.choice بدلاً من random.choice random.SystemRandom().choice في تطبيق يتطلب PRNG آمنًا مدمرًا ، ونظرًا لشعبية هذا السؤال ، أراهن أن هذا الخطأ قد تم إجراؤه عدة مرات بالفعل.

إذا كنت تستخدم python3.6 أو أعلى ، فيمكنك استخدام وحدة secrets الجديدة.

''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))

تناقش مستندات الوحدة النمطية أيضًا الطرق المريحة لتوليد الرموز الآمنة وأفضل الممارسات .

Question

أريد إنشاء سلسلة من الحجم N.

يجب أن يتكون من أرقام وحروف إنجليزية كبيرة مثل:

  • 6U1S75
  • 4Z4UKK
  • U911K4

كيف يمكنني تحقيق ذلك بطريقة pythonic ؟




طريقة أسرع وأسهل وأكثر مرونة للقيام بذلك هي استخدام وحدة strgen ( pip install StringGenerator ).

إنشاء سلسلة عشوائية من 6 أحرف مع الأحرف الكبيرة والأرقام:

>>> from strgen import StringGenerator as SG
>>> SG("[\u\d]{6}").render()
u'YZI2CI'

احصل على قائمة فريدة:

>>> SG("[\l\d]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']

ضمان حرف "خاص" واحد في السلسلة:

>>> SG("[\l\d]{10}&[\p]").render()
u'jaYI0bcPG*0'

لون HTML عشوائي:

>>> SG("#[\h]{6}").render()
u'#CEdFCa'

إلخ

نحن بحاجة إلى أن ندرك أن هذا:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

قد لا يحتوي على رقم (أو حرف كبير) فيه.

strgen هو أسرع في وقت المطور من أي من الحلول المذكورة أعلاه. الحل من Ignacio هو أسرع أداء وقت التشغيل وهو الإجابة الصحيحة باستخدام مكتبة Python القياسية. لكنك لن تستخدمه في هذا الشكل. ستحتاج إلى استخدام SystemRandom (أو الرجوع إذا لم يكن متاحًا) ، تأكد من تمثيل مجموعات الأحرف المطلوبة ، أو استخدام unicode (أو لا) ، تأكد من أن الاستدعاءات المتتالية تنتج سلسلة فريدة ، استخدم مجموعة فرعية من إحدى فئات أحرف وحدة الصفيف ، كل هذا يتطلب الكثير من التعليمات البرمجية أكثر من الإجابات المقدمة. إن المحاولات العديدة لتعميم الحل لها جميع القيود التي تحلها strgen بقدر أكبر من الإيجاز والطاقة التعبيرية باستخدام لغة قالب بسيطة.

إنها على PyPI:

pip install StringGenerator

الإفصاح: أنا مؤلف وحدة strgen.




من Python 3.6 يجب عليك استخدام وحدة secrets إذا كنت بحاجة إلى أن يكون آمنًا بشكل مشفر بدلاً من الوحدة random (وإلا تكون هذه الإجابة مماثلة لواحدةIgnacio Vazquez-Abrams):

from secrets import choice
import string

''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])

ملاحظة إضافية واحدة: الفهم قائمة أسرع في حالة str.join من استخدام تعبير مولد!




إذا كنت بحاجة إلى سلسلة عشوائية بدلاً من واحدة عشوائية زائفة ، فيجب استخدام os.urandom كمصدر

from os import urandom
from itertools import islice, imap, repeat
import string

def rand_string(length=5):
    chars = set(string.ascii_uppercase + string.digits)
    char_gen = (c for c in imap(urandom, repeat(1)) if c in chars)
    return ''.join(islice(char_gen, None, length))



(1) سيعطيك هذا كل الحروف والأرقام:

import string, random
passkey=''
for x in range(8):
    if random.choice([1,2]) == 1:
        passkey += passkey.join(random.choice(string.ascii_uppercase))
    else:
        passkey += passkey.join(random.choice(string.digits))
print passkey 

(2) إذا أردت لاحقًا تضمين أحرف صغيرة في مفتاحك ، فسيعمل هذا أيضًا:

import string, random
passkey=''
for x in range(8):
    if random.choice([1,2]) == 1:
        passkey += passkey.join(random.choice(string.ascii_letters))
    else:
        passkey += passkey.join(random.choice(string.digits))
print passkey  



لقد وجدت هذا أبسط وأنظف.

str_Key           = ""
str_FullKey       = "" 
str_CharacterPool = "01234ABCDEFfghij~>()"
for int_I in range(64): 
    str_Key = random.choice(str_CharacterPool) 
    str_FullKey = str_FullKey + str_Key 

كل ما عليك هو تغيير 64 لتغيير الطول ، وتغيير CharacterPool للقيام بالألفا alpha الرقمية فقط أو الرقمية فقط أو أحرف غريبة أو أي شيء تريده.




طريقتين:

import random, math

def randStr_1(chars:str, length:int) -> str:
    chars *= math.ceil(length / len(chars))
    chars = letters[0:length]
    chars = list(chars)
    random.shuffle(characters)

    return ''.join(chars)

def randStr_2(chars:str, length:int) -> str:
    return ''.join(random.choice(chars) for i in range(chars))


المعيار:

from timeit import timeit

setup = """
import os, subprocess, time, string, random, math

def randStr_1(letters:str, length:int) -> str:
    letters *= math.ceil(length / len(letters))
    letters = letters[0:length]
    letters = list(letters)
    random.shuffle(letters)
    return ''.join(letters)

def randStr_2(letters:str, length:int) -> str:
    return ''.join(random.choice(letters) for i in range(length))
"""

print('Method 1 vs Method 2', ', run 10 times each.')

for length in [100,1000,10000,50000,100000,500000,1000000]:
    print(length, 'characters:')

    eff1 = timeit("randStr_1(string.ascii_letters, {})".format(length), setup=setup, number=10)
    eff2 = timeit("randStr_2(string.ascii_letters, {})".format(length), setup=setup, number=10)
    print('\t{}s : {}s'.format(round(eff1, 6), round(eff2, 6)))
    print('\tratio = {} : {}\n'.format(eff1/eff1, round(eff2/eff1, 2)))

انتاج :

Method 1 vs Method 2 , run 10 times each.

100 characters:
    0.001411s : 0.00179s
    ratio = 1.0 : 1.27

1000 characters:
    0.013857s : 0.017603s
    ratio = 1.0 : 1.27

10000 characters:
    0.13426s : 0.151169s
    ratio = 1.0 : 1.13

50000 characters:
    0.709403s : 0.855136s
    ratio = 1.0 : 1.21

100000 characters:
    1.360735s : 1.674584s
    ratio = 1.0 : 1.23

500000 characters:
    6.754923s : 7.160508s
    ratio = 1.0 : 1.06

1000000 characters:
    11.232965s : 14.223914s
    ratio = 1.0 : 1.27

أداء الأسلوب الأول هو أفضل.




طريقة أبسط وأسرع ولكن أقل عشوائية هي استخدام random.sample بدلاً من اختيار كل حرف على حدة ، إذا تم السماح بـ n-repetitions ، قم بتكبير الأساس العشوائي الخاص بك بواسطة n أوقات مثل

import random
import string

char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))

ملاحظة: random.sample يمنع إعادة استخدام الأحرف ، مما يؤدي إلى تضاعف حجم مجموعة الأحرف مما يجعل التكرار المتعدد ممكنًا ، ولكن لا يزال أقل احتماليةً عندئذٍ في اختيار عشوائي خالص. إذا ذهبنا لسلسلة من الطول 6 ، واخترنا الحرف "X" كأول حرف ، في مثال الاختيار ، فإن احتمالات الحصول على الحرف "X" للحرف الثاني هي نفس احتمالات الحصول على "X" مثل الشخصية الأولى. في تطبيق random.sample ، فإن احتمالات الحصول على "X" كأي حرف لاحق هي 6/7 فقط فرصة الحصول عليها كحرف أول







>>> import random
>>> str = []
>>> chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
>>> num = int(raw_input('How long do you want the string to be?  '))
How long do you want the string to be?  10
>>> for k in range(1, num+1):
...    str.append(random.choice(chars))
...
>>> str = "".join(str)
>>> str
'tm2JUQ04CK'

تختار الدالة random.choice إدخال عشوائي في قائمة. يمكنك أيضًا إنشاء قائمة حتى يمكنك إلحاق الحرف في العبارة. في نهاية str هو ['t' ، 'm' ، '2' ، 'J' ، 'U' ، 'Q' ، '0' ، '4' ، 'C' ، 'K'] ، ولكن str = "".join(str) يعتني بذلك ، 'tm2JUQ04CK' مع 'tm2JUQ04CK' .

أتمنى أن يساعدك هذا!




استناداً إلى إجابة أخرى ، معظم الطرق خفيفة الوزن لإنشاء سلسلة عشوائية ورقم ست عشري عشوائي ، أفضل إصدار من الإجابة المقبولة سيكون:

('%06x' % random.randrange(16**6)).upper()

أسرع بكثير.




import string
from random import *
characters = string.ascii_letters + string.punctuation  + string.digits
password =  "".join(choice(characters) for x in range(randint(8, 16)))
print password