I hope it's Monday-itis kicking in at the moment, but something I feel should be quite easy - or at least elegant - is giving me a brain fart. The use case is this:
Find all possible combinations of a specific word, where letters can be any case or replaced with letters. For instance:
Word: 'Password'
Combinations: 'PASSWORD', 'P@ssw0rd', 'p@55w0rD' ...
I do not want to write 7 loops to find this out, even though it's a once off script we'll never ever use again.
import itertools
places = [
"Pp",
"Aa@",
"Ss5",
"Ss5",
"Ww",
"Oo0",
"Rr",
"Dd",
]
for letters in itertools.product(*places):
print "".join(letters)
If you need to handle arbitrary words, then you'll need to write code to create the places
list from the string.
The main issue with this problem, is that not all letters can be translated to symbols or numbers. You have to create a dictionary where the key is a lower case letter and the value is a list of all possible replacement of that letter:
{'a':['a','A','@'],...,'s':['s','S','5'],...,}
Once your dictionary is built, the rest is just a matter of a simple Cartesian product of the different lists in the right order.
I'd use itertools.product
:
import itertools
symbols = dict(a="@", s="5", o="0") # char -> str
text = "password"
print list(itertools.product(*[[letter, letter.upper()] + list(symbols.get(letter, "")) for letter in text.lower()])
itertools.product is what you're searching for:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from itertools import product
def getAllCombinations(password):
leet = ["Aa@","Bb","Cc", "Dd","Ee","Ff","Gg","Hh","Ii","Jj","Kk",
"Ll","Mm","Nn","Oo0","Pp","Qq","Rr","Ss5","Tt","Uu","Vv",
"Ww","Xx","Yy","Zz"]
getPlaces = lambda password: [leet[ord(el.upper()) - 65] for el in password]
for letters in product(*getPlaces(password)):
yield "".join(letters)
for el in getAllCombinations("Password"):
print el
If you are curious what the asterisk * means, here you are: foggy on asterisk in python