임의의 문자열과 임의의 16 진수를 만드는 가장 간단한 방법


96

다음과 같이 임의의 30 자 문자열을 만드는 가장 간단한 방법은 무엇입니까?

ufhy3skj5nca0d2dfh9hwd2tbk9sw1

그리고 다음과 같은 16 진수 30 자리 숫자?

8c6f78ac23b4a7b8c0182d7a89e9b1


3
어떻게 (왜?) (잘 만들어진) 답변이 받아 들여지지 않았습니까?
r2evans

답변:


127

16 진수 출력을 위해 더 빠른 것을 얻었습니다. 위와 동일한 t1 및 t2 사용 :

>>> t1 = timeit.Timer("''.join(random.choice('0123456789abcdef') for n in xrange(30))", "import random")
>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t3 = timeit.Timer("'%030x' % random.randrange(16**30)", "import random")
>>> for t in t1, t2, t3:
...     t.timeit()
... 
28.165037870407104
9.0292739868164062
5.2836320400238037

t3 임의 모듈을 한 번만 호출하고 목록을 작성하거나 읽을 필요가 없으며 나머지는 문자열 형식으로 수행합니다.


5
좋은. 30 16 진수 길이의 임의의 숫자를 생성하고 인쇄하십시오. 지적하면 분명합니다. 멋지네요.
eemz

흥미롭게도 Python (및 임의 모듈)이 기본적으로 bigint를 처리한다는 사실을 잊었습니다.
wump

3
사용에 대한 yaronf의 답변을 참조하십시오 string.hexdigits. stackoverflow.com/a/15462293/311288 " string.hexdigitsreturns 0123456789abcdefABCDEF(소문자 및 대문자 모두), [...]. 대신 random.choice('0123456789abcdef')."
Thomas

3
getrandbits대신 사용 randrange하여 더 빠르게 만듭니다.
robinst

@robinst는 좋은 지적이 있습니다. '%030x' % random.getrandbits(60)더 빨리보다 '%030x' % random.randrange(16**30)가 큰 int 치의에서 / 어떤 변환을 할 필요가 없습니다하지 않을 가능성이 있기 때문에,
댄 렌스키

80

30 자리 16 진수 문자열 :

>>> import os,binascii
>>> print binascii.b2a_hex(os.urandom(15))
"c84766ca4a3ce52c3602bbf02ad1f7"

장점은 이것이 OS에서 직접 임의성을 가져오고 random ()보다 더 안전하고 빠르며 시드 할 필요가 없다는 것입니다.


흥미롭고 그가 원하는 30 자리 16 진수를 생성하기위한 좋은 선택 일 것입니다. 아마도 urandom과 슬라이스 연산자를 사용하여 영숫자 문자열을 생성 할 수도 있습니다.
eemz

binascii의 다른 함수를 살펴 보았습니다. base64와 uuencode가 있지만 원하는 첫 번째 유형의 문자열 (base36)을 생성 할 방법이 없습니다.
wump

1
이것은 세션 토큰에 사용될 정도로 무작위적이고 고유합니까?
moraes


길이를 어떻게 지정합니까?
3kstc

55

Py3.6 +에서 또 다른 옵션은 새로운 표준 secrets모듈 을 사용하는 것입니다 .

>>> import secrets
>>> secrets.token_hex(15)
'8d9bad5b43259c6ee27d9aadc7b832'
>>> secrets.token_urlsafe(22)   # may include '_-' unclear if that is acceptable
'teRq7IqhaRU0S3euX1ji9f58WzUkrg'

28
import string
import random
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)]
str = "".join(lst)
print str
ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb

6
및 random.choice (string.hexdigits)
eemz

1
더 안전한 암호화 방식을 선호 할 수 있습니다random.SystemRandom().choice
Brian M. Hunt

1
xrange ()는 range () 여야합니다.-NameError : 이름 'xrange'가 정의되지 않았습니다.
Caleb Bramwell

xrange는 python 2.x에서 정확하고 일반적으로 더 좋습니다.
jcdyer

25

여기보다 훨씬 빠른 솔루션 :

timeit("'%0x' % getrandbits(30 * 4)", "from random import getrandbits")
0.8056681156158447

한 사용자는 정확한 기준을 얻기 위해 동일한 시스템에서 모든 방법을 시도해야합니다. 하드웨어 사양은 큰 차이를 만들 수 있습니다. >>>> timeit.timeit ( " '% 0x'% getrandbits (30 * 4)", "from random import getrandbits") 0.2471246949999113 </ pre>
ptay

감사합니다. 위의 다른 것보다 훨씬 빠릅니다. %timeit '%030x' % randrange(16**30)While 루프 당 1.61 μs의 : 1000000 개 루프, 3의 최선을 제공 %timeit '%0x' % getrandbits(30 * 4)루프 당 396 NS : 1000000 개 루프, 3의 최선을 제공합니다
frmdstryr

15

참고 : random.choice(string.hexdigits)은 (소문자와 대문자 모두) string.hexdigits반환 되므로 잘못된 0123456789abcdefABCDEF결과를 얻을 수 있으므로 16 진수 'c'가 숫자 '7'보다 2 배 더 많이 나타날 가능성이 있습니다. 대신 random.choice('0123456789abcdef').


6

다른 방법 :

from Crypto import Random
import binascii

my_hex_value = binascii.hexlify(Random.get_random_bytes(30))

요점은 다음 과 같습니다 . 바이트 값은 항상 16 진수 값과 같습니다 .


5

단선 기능 :

import random
import string

def generate_random_key(length):
    return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length))

print generate_random_key(30)

3
In [1]: import random                                    

In [2]: hex(random.getrandbits(16))                      
Out[2]: '0x3b19'

참고 :이 답변은 품질이 낮은 것으로 표시되었으므로 개선 할 수 있습니다.
oguz ismail

개선을위한 제안 사항이 있습니까?

몰라요. 난 그냥 당신이 알아야 할 생각이
오구 즈 이스마일

2

부수적으로 이것은 timeit제안 된 두 가지 접근 방식을 사용한 결과입니다 .

사용 random.choice():

>>> t1 = timeit.Timer("''.join(random.choice(string.hexdigits) for n in xrange(30))", "import random, string")
>>> t1.timeit()
69.558588027954102

사용 binascii.b2a_hex():

>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t2.timeit()
16.288421154022217

2

jcdyer가 언급 한 것에 비해 더 빠른 것이 있습니다. 이것은 그의 가장 빠른 방법의 ~ 50 %를 차지합니다.

from numpy.random.mtrand import RandomState
import binascii
rand = RandomState()

lo = 1000000000000000
hi = 999999999999999999
binascii.b2a_hex(rand.randint(lo, hi, 2).tostring())[:30]

>>> timeit.Timer("binascii.b2a_hex(rand.randint(lo,hi,2).tostring())[:30]", \
...                 'from __main__ import lo,hi,rand,binascii').timeit()
1.648831844329834         <-- this is on python 2.6.6
2.253110885620117         <-- this on python 2.7.5

base64에서 원하는 경우 :

binascii.b2a_base64(rand.randint(lo, hi, 3).tostring())[:30]

randint (마지막 인수)에 전달 된 크기 매개 변수를 변경하여 요구 사항에 따라 출력 길이를 변경할 수 있습니다. 따라서 60 자의 경우 :

binascii.b2a_hex(rand.randint(lo, hi, 4).tostring())[:60]

약간의 변형 : binascii.b2a_hex(np.random.rand(np.ceil(N/16)).view(dtype=int))[:N]여기서 N=30.
dan-man

@ dan-man이 선택적 방법에 감사드립니다. 그러나 나는 그것이 적어도 5 배 더 많은 시간을 소비한다는 것을 알았습니다. 그것도 눈치 채 셨나요?
에단

0

@eemz 솔루션보다 빠르게 수행되고 완전한 영숫자 인 믹스에 하나 이상의 답변을 추가합니다. 이것은 16 진법 답을 주지 않는다는 점에 유의하십시오 .

import random
import string

LETTERS_AND_DIGITS = string.ascii_letters + string.digits

def random_choice_algo(width):
  return ''.join(random.choice(LETTERS_AND_DIGITS) for i in range(width))

def random_choices_algo(width):
  return ''.join(random.choices(LETTERS_AND_DIGITS, k=width))


print(generate_random_string(10))
# prints "48uTwINW1D"

빠른 벤치 마크 결과

from timeit import timeit
from functools import partial

arg_width = 10
print("random_choice_algo", timeit(partial(random_choice_algo, arg_width)))
# random_choice_algo 8.180561417000717
print("random_choices_algo", timeit(partial(random_choices_algo, arg_width)))
# random_choices_algo 3.172438014007639

0

이것은 확실히 가장 가벼운 버전은 아니지만 무작위이며 원하는 알파벳 / 길이를 쉽게 조정할 수 있습니다.

import random

def generate(random_chars=12, alphabet="0123456789abcdef"):
    r = random.SystemRandom()
    return ''.join([r.choice(alphabet) for i in range(random_chars)])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.