randomモジュールのrandint関数やchoice関数、choices関数とstringモジュールで定義されている定数を組み合わせてランダムな文字列を生成する方法を紹介する。
import random
# random.randint関数とchr関数を使う例
start = ord('a')
end = ord('z')
n = 10
tmp = [chr(random.randint(start, end)) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:rhnravmvxd
# random.choice関数とchr関数を使う例
tmp = [chr(random.choice(range(start, end+1))) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:xprounzvjn
# random.choices関数はシーケンスを取り扱うので文字列を与えてもよい
lowercases = 'abcdefghijklmnopqrstuvwxyz'
tmp = [random.choice(lowercases) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:bchjeiuevi
# ASCII文字のコードポイントは連続していない
start = ord('A')
end = ord('z')
tmp = [chr(random.randint(start, end)) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:SEo[jypUNa
# random.choices関数を使う例
lowercases = 'abcdefghijklmnopqrstuvwxyz'
uppercases = lowercases.upper()
letters = lowercases + uppercases
tmp = random.choices(letters, k=n)
result = ''.join(tmp)
print(result) # 出力例:sKbUUDAKXj
# stringモジュールを使う例
from string import ascii_lowercase, ascii_uppercase, ascii_letters, digits
print(ascii_lowercase) # abcdefghijklmnopqrstuvwxyz
print(ascii_uppercase) # ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(digits) # 0123456789
def get_random_string(n, lower=True, upper=True, numbers=False):
chars = ''
if lower:
chars += ascii_lowercase
if upper:
chars += ascii_uppercase
if numbers:
chars += digits
return ''.join(random.choices(chars, k=n))
result = get_random_string(10, numbers=True)
print(result) # 出力例:8yoUtn9vYM
辞書のキーにするなどの目的で、(意味はなくてもよいので)ランダムな文字列を作成したくなる場合がある。簡単に考えつくのは以下のような方法だ。
import random
start = ord('a')
end = ord('z')
n = 10
tmp = [chr(random.randint(start, end)) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:rhnravmvxd
これはrandomモジュールのrandint関数*1に、生成する文字列の範囲として'a'から'z'を指定して、その範囲に含まれる文字のいずれかを変数nに指定した数(ここでは10)だけchr関数で生成して、最後に1つの文字列にまとめている(上のリスト内包表記は個々の文字を要素とするリストが生成される)。
*1 この記事で紹介するrandint関数などは実際にはrandom.Randomクラスのメソッドだ。だが、randomモジュールのドキュメントでは「整数用の関数」などと表現されているとともに「random.randint(start, end)」のように関数的に使っているので、ここでも関数という呼び方をする。
これと同じことはrandomモジュールのchoice関数を使っても記述できる。
tmp = [chr(random.choice(range(start, end+1))) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:xprounzvjn
ここで使用しているrandom.choice関数は与えられたシーケンスからランダムに要素を1つ取り出す。上のコードではrange関数で生成する文字の範囲を指定することで、その範囲からランダムにコードポイントを取り出し、chr関数で対応する文字を得ている(それを文字数nだけ繰り返す)。range関数には終端としてord('z')+1を指定する必要がある点には注意が必要だ。
上のコードではrange関数を使って文字範囲を指定しているが、random.choice関数はシーケンスを受け取るので、単純に文字列を指定するだけでもよい。以下がその例だ。
lowercases = 'abcdefghijklmnopqrstuvwxyz'
tmp = [random.choice(lowercases) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:bchjeiuevi
この例では小文字アルファベットを列挙した文字列lowercasesを作成し、それをrandom.choice関数に渡している。ord関数でコードポイントを得るよりも、こちらの方が直感的かもしれない。
ASCIIの範囲で小文字と大文字(と数字)のコードポイントが連続していない点も考慮する必要があるかもしれない。例えば、アルファベットの大文字小文字だけからなるランダムな文字列を得ようとして、以下のようなコードを書くと記号類が混在する文字列が得られることもある(以下を何度か試すと、そうした結果が得られるはずだ)。
start = ord('A')
end = ord('z')
tmp = [chr(random.randint(start, end)) for _ in range(n)]
result = ''.join(tmp)
print(result) # 出力例:SEo[jypUNa
こうしたことからも生成したい文字の範囲を文字列の形で直接指定するのが適切だろう。
また、これまでのコードでは必要な数の文字を得るためにリスト内包表記を使っていたが、random.choices関数でkパラメーターに取り出す要素の数を指定すると、リスト内包表記を使わなくても同じことができる。random.choices関数は渡したシーケンスからランダムに要素を取り出した要素数kのリストを返す関数だ(要素の重複あり)。
lowercases = 'abcdefghijklmnopqrstuvwxyz'
uppercases = lowercases.upper()
letters = lowercases + uppercases
tmp = random.choices(letters, k=n)
result = ''.join(tmp)
print(result) # 出力例:sKbUUDAKXj
この例ではアルファベット小文字からなる文字列lowercasesと大文字からなる文字列uppercasesと、それらをまとめた文字列lettersを作成し、random.choices関数には文字列lettersと要素数としてn(=10)を渡している。リスト内包表記を使わないのでスッキリとしたコードになっているのが分かる。
特定の文字範囲をrandom.choice関数やrandom.choices関数に渡すのであれば、上のコードのようにそれらをまとめた文字列をいちいち定義する必要があるが、stringモジュールにはアルファベット小文字や大文字、大文字と小文字、数字などを定義した定数が定義されている(ドキュメントでは定数とあるが、実際には変更可能なことには注意)。
from string import ascii_lowercase, ascii_uppercase, ascii_letters, digits
print(ascii_lowercase) # abcdefghijklmnopqrstuvwxyz
print(ascii_uppercase) # ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(digits) # 0123456789
これらの値とrandom.choices関数を組み合わせて、ランダムな文字列を得る関数を定義すると次のようになるだろう。
def get_random_string(n, lower=True, upper=True, numbers=False):
chars = ''
if lower:
chars += ascii_lowercase
if upper:
chars += ascii_uppercase
if numbers:
chars += digits
return ''.join(random.choices(chars, k=n))
result = get_random_string(10, numbers=True)
print(result) # 出力例:8yoUtn9vYM
ここではlowerパラメーター、upperパラメーター、numbersパラメーターにTrue/Falseを指定することで、どの種類の文字列からランダムな文字列を生成するかを指定できるようにしている。
Copyright© Digital Advantage Corp. All Rights Reserved.