import random
import string
def random_char(y):
return ''.join(random.choice(string.ascii_uppercase) for x in range(y))
p1 = str(random.randrange(1, 99))
p2 = str(random_char(5))
p3 = str(random.randrange(1, 9))
p4 = str(random_char(2))
p5 = str(random.randrange(1, 9))
p6 = str(random_char(1)) # Y
p7 = str(random.randrange(1, 9)) # 7
p8 = str(random_char(3)) # AUS
result = p1 + p2+p3+p4+p5+p6+p7+p8
print(result)
I generate a specific code like "31SPZVG2CZ2R8WFU" How can i do it in a more elegant way?
2 Answers 2
In your random_char
function, you don't use x
at all. Replace it with _
(it's conventional in python to use _
for throwaway variables). y
could also be renamed to something more descriptive. The name of the function could also be renamed to random_chars
since you're generating one or more of them.
Also, use string formatting instead of all those extra variables:
def generate_key():
return (f"{random.randrange(1, 9)}{random_chars(5)}{random.randrange(1, 9)}{random_chars(2)}"
f"{random.randrange(1, 9)}{random_chars(1)}{random.randrange(1, 9)}{random_chars(3)}")
Note that the f-strings are available for Python versions >= 3.6
As a side note, there's this nice exrex which can:
Generate all - or random - matching strings to a given regular expression and more. It's pure python, without external dependencies.
Given some pattern (similar to what you want):
r"(\d[A-Z]{1,4}){4}"
(...){4}
matches the previous token exactly 4 times.\d
matches a digit (equivalent to[0-9]
)[A-Z]{1,4}
matches the previous token between 1 and 4 times, as many times as possible, giving back as needed (greedy)A-Z
matches a single character in the range between A (index 65) and Z (index 90) (case sensitive)
Note: I'm not a regex expert so there might be an easier / more correct version of this.
I think you can use this regex which returns exactly the pattern you want: \d{1,2}[A-Z]{5}\d[A-Z]{2}\d[A-Z]{1}\d[A-Z]{3}
Your entire code could be rewritten as:
import exrex
random_key = exrex.getone(r'(\d[A-Z]{1,4}){4}')
print(random_key)
Which would generate:
'3C2BBV3NGKJ2XYJ'
For more information about regular expressions feel free to search on the internet to get familiar with them. For tests, I usually use regex101
-
\$\begingroup\$ As an advice, before accepting an answer try to wait 1-2 days to see alternative solutions/improvements. \$\endgroup\$Grajdeanu Alex– Grajdeanu Alex2021年09月23日 12:57:05 +00:00Commented Sep 23, 2021 at 12:57
-
\$\begingroup\$ Is this right? The pattern you're using doesn't seem to follow the OP's, for instance having two leading digits. \$\endgroup\$Reinderien– Reinderien2021年09月23日 13:26:29 +00:00Commented Sep 23, 2021 at 13:26
-
1\$\begingroup\$ @Reinderien It's just an example. I've specified in my answer that this regex might not be as the one in the question. And with a bit of effort from OP it can be easily modified/customized. More, that is an alternate solution for OP to have in mind ^^. //L.E: added a similar regex \$\endgroup\$Grajdeanu Alex– Grajdeanu Alex2021年09月23日 13:40:55 +00:00Commented Sep 23, 2021 at 13:40
Instead of treating number and letter parts differently, you could use random.choice
for both and save some code:
import random
from string import ascii_uppercase
spec = [
range(1, 99), *[ascii_uppercase] * 5,
range(1, 9), *[ascii_uppercase] * 2,
range(1, 9), *[ascii_uppercase],
range(1, 9), *[ascii_uppercase] * 3,
]
print(''.join(str(random.choice(pool)) for pool in spec))
-
\$\begingroup\$ Wow, cool. Could you please explain how this code works exactly? I am just learning \$\endgroup\$Bogdan Mind– Bogdan Mind2021年09月23日 18:40:10 +00:00Commented Sep 23, 2021 at 18:40
-
1\$\begingroup\$ It just builds a list of sequences (try
print(spec)
) and then picks an element from each and concatenates them all. \$\endgroup\$no comment– no comment2021年09月23日 18:57:48 +00:00Commented Sep 23, 2021 at 18:57
1-2 digits + 5*random uppercased letters + ...
or it can be any random string? \$\endgroup\$