web-dev-qa-db-ja.com

大文字と数字を使ったランダムな文字列生成

サイズNの文字列を生成します。

次のような数字と大文字の英字で構成する必要があります。

  • 6U1S75
  • 4Z4UKK
  • U911K4

どうしたらこれを Pythonic の方法で達成できますか?

1164
Hellnar

1行で回答:

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

または random.choices() を使用してPython 3.6で始まるより短い

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

暗号的に安全なバージョン。 https://stackoverflow.com/a/23728630/2213647を参照してください

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

詳細に、さらに再利用するためのクリーンな関数を使用:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

どのように機能しますか?

一般的なASCII文字のシーケンスを含むモジュールstringと、ランダム生成を処理するモジュールrandomをインポートします。

string.ascii_uppercase + string.digitsは、大文字のASCII文字と数字を表す文字のリストを連結するだけです。

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

次に、リスト内包表記を使用して、「n」個の要素のリストを作成します。

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

上記の例では、[を使用してリストを作成していますが、id_generator関数には含まれていないため、Pythonはメモリ内にリストを作成しませんが、実行中の要素を1つずつ(詳細については こちら )。

文字列elemを 'n'回作成する代わりに、Pythonに、一連の文字から選択した 'n'回のランダムな文字を作成するように要求します。

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

したがって、random.choice(chars) for _ in range(size)は実際にsize文字のシーケンスを作成しています。 charsからランダムに選択された文字:

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

次に、空の文字列でそれらを結合するだけで、シーケンスは文字列になります。

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
2364

このスタックオーバーフローの問題は、 "ランダムな文字列のPython"に対するGoogleの現在のトップ結果です。現在のトップの答えは:

''.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()を使用すると、* nixマシンでは/ dev/urandomが、WindowsではCryptGenRandom()が使用されます。これらは暗号的に安全なPRNGです。安全なPRNGを必要とするアプリケーションでrandom.SystemRandom().choiceの代わりにrandom.choiceを使用することは潜在的に壊滅的である可能性があり、この質問の人気を考えると、私は間違いが既に何度もなされたことを確信します。

Python3.6以上を使っているなら、new secrets モジュールを使うことができます。

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

モジュールのドキュメントでは 安全なトークンを生成するための便利な方法についても議論していますベストプラクティス

508
Randy Marsh

Pythonの組み込みのuuidを使うだけです。

UUIDが目的にかなっていない場合は、組み込みの uuid パッケージを使用してください。

ワンラインソリューション:

import uuid; uuid.uuid4().hex.upper()[0:6]

詳細バージョンでは:

例:

import uuid
uuid.uuid4() #uuid4 => full random uuid
# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')

あなたが正確にあなたのフォーマット(例えば "6U1S75")を必要とするならば、あなたはこれをこのようにすることができます:

import uuid

def my_random_string(string_length=10):
    """Returns a random string of length string_length."""
    random = str(uuid.uuid4()) # Convert UUID format to a Python string.
    random = random.upper() # Make all characters uppercase.
    random = random.replace("-","") # Remove the UUID '-'.
    return random[0:string_length] # Return the random string.

print(my_random_string(6)) # For example, D9E50C
166
Bijan

より簡単で、速いがわずかにランダムではない方法は、各文字を別々に選択する代わりにrandom.sampleを使用することです。

import random
import string

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

注:random.sampleは文字の再利用を防ぎ、文字セットのサイズを掛けることで複数の繰り返しが可能になりますが、それでもそれらが純粋にランダムに選択される可能性は低いです。長さ6の文字列を検索し、最初の文字として 'X'を選択した場合、選択例では、2番目の文字として 'X'を取得する確率は、最初の文字として 'X'を取得する確率と同じです。最初の文字random.sampleの実装では、後続の文字として 'X'を取得する可能性は6/7ですが、最初の文字として取得する可能性はわずかです。

44
Anurag Uniyal
import uuid
lowercase_str = uuid.uuid4().hex  

lowercase_str'cea8b32e00934aaea8c005a35d85a5c0'のようなランダムな値です

uppercase_str = lowercase_str.upper()

uppercase_str'CEA8B32E00934AAEA8C005A35D85A5C0'です

29
Savad KP

Ignacioから答えを取って、これはPython 2.6で動作します:

import random
import string

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

出力例

JQUBT2

20
quamrana

これを行うより速く、より簡単で、より柔軟な方法は 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']

保証 文字列内の1つの "特殊"文字

>>> 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モジュールの作者です。

19
Paul Wolf

別のStack Overflowの回答に基づいて、ランダムな文字列とランダムな16進数を作成するための最も軽量な方法

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

はるかに高速。

9
Gubbi

私は誰もまだこれに答えていないと思いました(笑)しかし、ねえ、これが私自身のやり方です。

import random

def random_alphanumeric(limit):
    #ascii alphabet of all alphanumerals
    r = (range(48, 58) + range(65, 91) + range(97, 123))
    random.shuffle(r)
    return reduce(lambda i, s: i + chr(s), r[:random.randint(0, len(r))], "")
9
nemesisfixx

擬似乱数 の代わりにランダムな文字列が必要な場合は、ソースとして 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))
9
John La Rooy

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)])

もう1つ注意してください:str.joinの場合、ジェネレータ式を使用するよりもリスト内包表記の方が高速です。

7
MSeifert

このメソッドは、Ignacioが投稿したrandom.choice()メソッドよりもわずかに速く、少し面倒です。

これは、擬似乱数アルゴリズムの性質を利用しており、各文字に対して新しい乱数を生成するよりもビット単位でシフトし、シフトする方が高速です。

# must be length 32 -- 5 bits -- the question didn't specify using the full set
# of uppercase letters ;)
_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'

def generate_with_randbits(size=32):
    def chop(x):
        while x:
            yield x & 31
            x = x >> 5
    return  ''.join(_ALPHABET[x] for x in chop(random.getrandbits(size * 5))).ljust(size, 'A')

... 5ビット数を一度に0から31まで取り去るジェネレータを作成する

...正しいビットを持つ乱数に対するジェネレータの結果をjoin()する

Timeitでは、32文字の文字列の場合、タイミングは次のとおりです。

[('generate_with_random_choice', 28.92901611328125),
 ('generate_with_randbits', 20.0293550491333)]

...しかし64文字の文字列の場合、randbitsは失います;)

私が同僚を本当に嫌いでない限り、私はおそらく本番コードでこのアプローチを決して使用しないでしょう。

edit:質問に合わせて更新され(大文字と数字のみ)、%と//ではなくビット演算子&と>>が使用されます。

7
Rob

私はこうします:

import random
from string import digits, ascii_uppercase

legals = digits + ascii_uppercase

def Rand_string(length, char_set=legals):

    output = ''
    for _ in range(length): output += random.choice(char_set)
    return output

あるいは単に:

def Rand_string(length, char_set=legals):

    return ''.join( random.choice(char_set) for _ in range(length) )
5
Carl Smith

Numpyのrandom.choice()関数を使う

import numpy as np
import string        

if __== '__main__':
    length = 16
    a = np.random.choice(list(string.ascii_uppercase + string.digits), length)                
    print(''.join(a))

ドキュメントはこちら http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html

4
Mudit Jain
>>> import string 
>>> import random

次のロジックでも6文字のランダムサンプルが生成されます

>>> print ''.join(random.sample((string.ascii_uppercase+string.digits),6))
JT7K3Q

6を掛ける必要はありません

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

TK82HK
4
user128956

(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  
3
Jacob

これは、Anurag Uniyalの回答と私が自分自身で作業していたことに対するものです。

import random
import string

oneFile = open('‪Numbers.txt', 'w')
userInput = 0
key_count = 0
value_count = 0
chars = string.ascii_uppercase + string.digits + string.punctuation

for userInput in range(int(input('How many 12 digit keys do you want?'))):
    while key_count <= userInput:
        key_count += 1
        number = random.randint(1, 999)
        key = number

        text = str(key) + ": " + str(''.join(random.sample(chars*6, 12)))
        oneFile.write(text + "\n")
oneFile.close()
3
Stopit Donk

機能的なpythonを楽しむあなたのために:

from itertools import imap, starmap, islice, repeat
from functools import partial
from string import letters, digits, join
from random import choice

join_chars = partial(join, sep='')
identity = lambda o: o

def irand_seqs(symbols=join_chars((letters, digits)), length=6, join=join_chars, select=choice, breakup=islice):
    """ Generates an indefinite sequence of joined random symbols each of a specific length
    :param symbols: symbols to select,
        [defaults to string.letters + string.digits, digits 0 - 9, lower and upper case English letters.]
    :param length: the length of each sequence,
        [defaults to 6]
    :param join: method used to join selected symbol, 
        [defaults to ''.join generating a string.]
    :param select: method used to select a random element from the giving population. 
        [defaults to random.choice, which selects a single element randomly]
    :return: indefinite iterator generating random sequences of giving [:param length]
    >>> from tools import irand_seqs
    >>> strings = irand_seqs()
    >>> a = next(strings)
    >>> assert isinstance(a, (str, unicode))
    >>> assert len(a) == 6
    >>> assert next(strings) != next(strings)
    """
    return imap(join, starmap(breakup, repeat((imap(select, repeat(symbols)), None, length))))

与えられたプールからランダムに選択されたシンボルの不定シーケンスを生成し、次にこのシーケンスを長さの部分に分割して結合することによって、結合されたランダムシーケンスの無限(無限)反復子を生成します。デフォルトでは、英数字のランダムなシーケンスを生成するだけですが、他のものを生成するように簡単に変更できます。

たとえば、数字のランダムなタプルを生成するには、

>>> irand_tuples = irand_seqs(xrange(10), join=Tuple)
>>> next(irand_tuples)
(0, 5, 5, 7, 2, 8)
>>> next(irand_tuples)
(3, 2, 2, 0, 3, 1)

nextを生成に使用したくない場合は、単に呼び出し可能にすることができます。

>>> irand_tuples = irand_seqs(xrange(10), join=Tuple)
>>> make_Rand_tuples = partial(next, irand_tuples) 
>>> make_Rand_tuples()
(1, 6, 2, 8, 1, 9)

シーケンスをその場で生成したい場合は、単にjoinをidentityに設定してください。

>>> irand_tuples = irand_seqs(xrange(10), join=identity)
>>> selections = next(irand_tuples)
>>> next(selections)
8
>>> list(selections)
[6, 3, 8, 2, 2]

あなたがより多くのセキュリティを必要とするならば他の人が述べたようにそれから適切な選択機能を設定します:

>>> from random import SystemRandom
>>> Rand_strs = irand_seqs(select=SystemRandom().choice)
'QsaDxQ'

デフォルトのセレクタはchoiceで、これは各チャンクに対して同じシンボルを複数回選択することができます。代わりに、同じチャンクに対して同じメンバーをせいぜい1回選択したい場合は、1つの使用法があります。

>>> from random import sample
>>> irand_samples = irand_seqs(xrange(10), length=1, join=next, select=lambda pool: sample(pool, 6))
>>> next(irand_samples)
[0, 9, 2, 3, 1, 6]

完全な選択を行うためにsampleをセレクタとして使用しているので、チャンクは実際には長さ1です。結合するには、次の完全に生成されたチャンクを取得するnextを呼び出します。

3
Samy Vilar
import random
q=2
o=1
list  =[r'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','s','0','1','2','3','4','5','6','7','8','9','0']
while(q>o):
    print("")

    for i in range(1,128):
        x=random.choice(list)
        print(x,end="")

ここで文字列の長さはforループ内、すなわち範囲内のi(i、length)に変更することができます。分かりやすい単純なアルゴリズムです。リストを使用するので、不要な文字は破棄できます。

2
lawlie8
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
2
Natasha

簡単なもの:

import string
import random
character = string.lowercase + string.uppercase + string.digits + string.punctuation
char_len = len(character)
# you can specify your password length here
pass_len = random.randint(10,20)
password = ''
for x in range(pass_len):
    password = password + character[random.randint(0,char_len-1)]
print password
1
Hackaholic
>>> 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関数はリストからランダムなエントリを選びます。 forステートメントにその文字を追加できるように、リストも作成します。末尾のstrは['t'、 'm'、 '2'、 'J'、 'U'、 'Q'、 '0'、 '4'、 'C​​'、 'K'ですが、str = "".join(str)'tm2JUQ04CK'であなたを残して、その世話をします。

お役に立てれば!

1
A.J. Uppal

私はほとんどすべての答えを見てきましたが、どれも簡単には見えません。ランダムなパスワードを作成するために一般的に使用されている passgen ライブラリを試すことをお勧めします。

長さ、句読点、数字、文字 および caseを選択して、ランダムな文字列を生成できます。

これがあなたの場合のコードです。

from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')
0
Sukumar Rdjf

2つの方法:

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

最初の方法のパフォーマンスは優れています。

0
Bi Ao

次の選択肢を提案します。

import crypt
n = 10
crypt.crypt("any sring").replace('/', '').replace('.', '').upper()[-n:-1]

妄想モード:

import uuid
import crypt
n = 10
crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
0
mrvol

時には0(ゼロ)とO(文字O)が混乱を招くことがあります。だから私は使う

import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
0
Aseem

python 3のインポート文字列、ランダム

'' .join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits)(範囲(15)の_の場合))

0
Foki