1

Something like this. I want to brute force all characters with word of 10 size

lookup = map(chr, range(32, 127))
for i in lookup:
    for j in lookup:
        for k in lookup:
            for l in lookup:
                for m in lookup:
                    for n in lookup:
                        for o in lookup:
                            for p in lookup:
                                for q in lookup:
                                    for r in lookup:
                                       print(r) # whatever

Here are my questions

1) Is there any better way?

2) One problem with this code is print(any of i j k ... r) not working, can you help me figure out the problem? if I give any string it is working but not the variables

3) I tried same with perl even there not able to print variables in the loop like i, j, .. r

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
rda3mon
  • 1,709
  • 4
  • 25
  • 37
  • 2
    You should define what you mean by better. – Tim McNamara Nov 07 '10 at 16:59
  • What are you trying to do? Are you trying to list every combination of 10-letter words? – Vivin Paliath Nov 07 '10 at 17:00
  • @Vivin: Yes This will print all possible combinations of 10 letter words – rda3mon Nov 07 '10 at 17:07
  • 1
    @Vivin I believe he's writing an incredibly naive password cracker. There are a million better solutions to this problem. – Rafe Kettler Nov 07 '10 at 17:09
  • 1
    @Rafe: Exactly, but with learning mindset. Can you tell me better ways of trying out all possible combinations? – rda3mon Nov 07 '10 at 17:14
  • 1
    @Ringo there isn't a "better way", it's just a foolish problem to try to solve. If you could do one billion combinations per second, your program would still take two thousand years to run. – hobbs Nov 07 '10 at 17:19
  • @hobbs: Could also take a few milliseconds, depends on the password ("aaaaaaaaaa" anyone?) =) – Björn Pollex Nov 07 '10 at 18:35
  • 1
    @Space, I've just changed mine to "zzzzzzzzzz", thanks. – Yuriy Faktorovich Nov 08 '10 at 17:45
  • @Space: I bet that `"aaaaaaaaaa"` is pretty safe from cracking by the code in the question. What machine can do 41402022394143222240 iterations in milliseconds? – tzot Nov 08 '10 at 20:11
  • @ΤΖΩΤΖΙΟΥ: Ok, you are right. But with " "*10 you are out of luck (damn, spaces get collapsed). – Björn Pollex Nov 08 '10 at 20:41
  • @Space: Yes, `"          "` is obviously the easiest, but your challenge was about `"aaaaaaaaaa"`. The combinations are 95¹⁰ (remember, `chr(127)` is not included in the original code) and the percentage of passwords that could be found in a few milliseconds is ridiculously miniscule to merit your previous warning-as-comment… – tzot Nov 08 '10 at 20:54
  • ΤΖΩΤΖΙΟΥ: It was supposed to be a joke, but i screwed it up by not thinking it through. – Björn Pollex Nov 08 '10 at 20:59

4 Answers4

13

While using the existing itertools package is normally better than rolling your own code, for educational value it's good to know how to do this yourself.

Obviously, nesting ten loops is not the best approach. I say "obviously" because it should immediately raise a red flag in your mind when you have to copy and paste code like that. It just doesn't look very elegant, does it?

There are several ways to solve this problem in a more elegant manner. One way is to use recursion. To do it recursively you need to break the problem into smaller pieces. These are the recursive rule and the base case. The recursive rule is where you assume you know how to solve a similar but slightly smaller version of the problem, and then use that to solve the larger case. The base case is where the recursion bottoms out because you can figure out the answer without any further recursion.

Recursive rule

In our case, how do you generate a 10-letter word? Let's say you know how to generate 9-letter words already. Then what?

for each 9-letter word:
    for each letter 'A' through 'Z':
        yield word + letter

It should be clear that this works the same for 9-letter words, 8-letter words, etc., with just a small adjustment to the outer loop. In general, to generate words of length n we combine every word of length n-1 with each letter of the alphabet. Or, in Python:

import string

def all_words(length):
    for word in all_words(length - 1):
        for letter in string.lowercase:
            yield word + letter

Let's try to run it. We'll start small. How about just all words of length 1 to start with?

>>> list(all_words(1))
  File "<stdin>", line 2, in all_words
  File "<stdin>", line 2, in all_words
  File "<stdin>", line 2, in all_words
  File "<stdin>", line 2, in all_words
RuntimeError: maximum recursion depth exceeded

Base case

Oops, what happened? Oh, right. The base case. To generate words of length 2 we recursively generate words of length 1. To generate words of length 1 we generate words of length 0. To generate words of length 0 we generate words of length -1.

Wait. What? Words of length -1? That doesn't make sense. At some point we need to stop recursing and simply return a result, otherwise we will recurse forever. This is the base case. The base case is the point at which you don't need to bother recursing because the answer is simple enough to figure out right away.

In our case, when we're asked to generate words of length 0, we really don't need to do any heavy lifting. You can see that the only "word" of length 0 is "", the empty string. It's the only string that has 0 characters in it. So when length is 0, let's just return the empty string:

import string

def all_words(length):
    # Base case
    if length == 0:
        yield ""
    # Recursive rule
    else:
        for word in all_words(length - 1):
            for letter in string.lowercase:
                yield word + letter

OK, let's try that again, shall we?

>>> list(all_words(2))
['aa', 'ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai', 'aj', 'ak', 'al', 'am', 'an', 'ao', 'ap', 'aq', 'ar', 'as', 'at', 'au', 'av', 'aw', 'ax', 'ay', 'az',
 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bk', 'bl', 'bm', 'bn', 'bo', 'bp', 'bq', 'br', 'bs', 'bt', 'bu', 'bv', 'bw', 'bx', 'by', 'bz',
 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'cg', 'ch', 'ci', 'cj', 'ck', 'cl', 'cm', 'cn', 'co', 'cp', 'cq', 'cr', 'cs', 'ct', 'cu', 'cv', 'cw', 'cx', 'cy', 'cz',
 'da', 'db', 'dc', 'dd', 'de', 'df', 'dg', 'dh', 'di', 'dj', 'dk', 'dl', 'dm', 'dn', 'do', 'dp', 'dq', 'dr', 'ds', 'dt', 'du', 'dv', 'dw', 'dx', 'dy', 'dz',
 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'eg', 'eh', 'ei', 'ej', 'ek', 'el', 'em', 'en', 'eo', 'ep', 'eq', 'er', 'es', 'et', 'eu', 'ev', 'ew', 'ex', 'ey', 'ez',
 'fa', 'fb', 'fc', 'fd', 'fe', 'ff', 'fg', 'fh', 'fi', 'fj', 'fk', 'fl', 'fm', 'fn', 'fo', 'fp', 'fq', 'fr', 'fs', 'ft', 'fu', 'fv', 'fw', 'fx', 'fy', 'fz',
 'ga', 'gb', 'gc', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gj', 'gk', 'gl', 'gm', 'gn', 'go', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gv', 'gw', 'gx', 'gy', 'gz',
 'ha', 'hb', 'hc', 'hd', 'he', 'hf', 'hg', 'hh', 'hi', 'hj', 'hk', 'hl', 'hm', 'hn', 'ho', 'hp', 'hq', 'hr', 'hs', 'ht', 'hu', 'hv', 'hw', 'hx', 'hy', 'hz',
 'ia', 'ib', 'ic', 'id', 'ie', 'if', 'ig', 'ih', 'ii', 'ij', 'ik', 'il', 'im', 'in', 'io', 'ip', 'iq', 'ir', 'is', 'it', 'iu', 'iv', 'iw', 'ix', 'iy', 'iz',
 'ja', 'jb', 'jc', 'jd', 'je', 'jf', 'jg', 'jh', 'ji', 'jj', 'jk', 'jl', 'jm', 'jn', 'jo', 'jp', 'jq', 'jr', 'js', 'jt', 'ju', 'jv', 'jw', 'jx', 'jy', 'jz',
 'ka', 'kb', 'kc', 'kd', 'ke', 'kf', 'kg', 'kh', 'ki', 'kj', 'kk', 'kl', 'km', 'kn', 'ko', 'kp', 'kq', 'kr', 'ks', 'kt', 'ku', 'kv', 'kw', 'kx', 'ky', 'kz',
 'la', 'lb', 'lc', 'ld', 'le', 'lf', 'lg', 'lh', 'li', 'lj', 'lk', 'll', 'lm', 'ln', 'lo', 'lp', 'lq', 'lr', 'ls', 'lt', 'lu', 'lv', 'lw', 'lx', 'ly', 'lz',
 'ma', 'mb', 'mc', 'md', 'me', 'mf', 'mg', 'mh', 'mi', 'mj', 'mk', 'ml', 'mm', 'mn', 'mo', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'mv', 'mw', 'mx', 'my', 'mz',
 'na', 'nb', 'nc', 'nd', 'ne', 'nf', 'ng', 'nh', 'ni', 'nj', 'nk', 'nl', 'nm', 'nn', 'no', 'np', 'nq', 'nr', 'ns', 'nt', 'nu', 'nv', 'nw', 'nx', 'ny', 'nz',
 'oa', 'ob', 'oc', 'od', 'oe', 'of', 'og', 'oh', 'oi', 'oj', 'ok', 'ol', 'om', 'on', 'oo', 'op', 'oq', 'or', 'os', 'ot', 'ou', 'ov', 'ow', 'ox', 'oy', 'oz',
 'pa', 'pb', 'pc', 'pd', 'pe', 'pf', 'pg', 'ph', 'pi', 'pj', 'pk', 'pl', 'pm', 'pn', 'po', 'pp', 'pq', 'pr', 'ps', 'pt', 'pu', 'pv', 'pw', 'px', 'py', 'pz',
 'qa', 'qb', 'qc', 'qd', 'qe', 'qf', 'qg', 'qh', 'qi', 'qj', 'qk', 'ql', 'qm', 'qn', 'qo', 'qp', 'qq', 'qr', 'qs', 'qt', 'qu', 'qv', 'qw', 'qx', 'qy', 'qz',
 'ra', 'rb', 'rc', 'rd', 're', 'rf', 'rg', 'rh', 'ri', 'rj', 'rk', 'rl', 'rm', 'rn', 'ro', 'rp', 'rq', 'rr', 'rs', 'rt', 'ru', 'rv', 'rw', 'rx', 'ry', 'rz',
 'sa', 'sb', 'sc', 'sd', 'se', 'sf', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sp', 'sq', 'sr', 'ss', 'st', 'su', 'sv', 'sw', 'sx', 'sy', 'sz',
 'ta', 'tb', 'tc', 'td', 'te', 'tf', 'tg', 'th', 'ti', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tq', 'tr', 'ts', 'tt', 'tu', 'tv', 'tw', 'tx', 'ty', 'tz',
 'ua', 'ub', 'uc', 'ud', 'ue', 'uf', 'ug', 'uh', 'ui', 'uj', 'uk', 'ul', 'um', 'un', 'uo', 'up', 'uq', 'ur', 'us', 'ut', 'uu', 'uv', 'uw', 'ux', 'uy', 'uz',
 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz',
 'wa', 'wb', 'wc', 'wd', 'we', 'wf', 'wg', 'wh', 'wi', 'wj', 'wk', 'wl', 'wm', 'wn', 'wo', 'wp', 'wq', 'wr', 'ws', 'wt', 'wu', 'wv', 'ww', 'wx', 'wy', 'wz',
 'xa', 'xb', 'xc', 'xd', 'xe', 'xf', 'xg', 'xh', 'xi', 'xj', 'xk', 'xl', 'xm', 'xn', 'xo', 'xp', 'xq', 'xr', 'xs', 'xt', 'xu', 'xv', 'xw', 'xx', 'xy', 'xz',
 'ya', 'yb', 'yc', 'yd', 'ye', 'yf', 'yg', 'yh', 'yi', 'yj', 'yk', 'yl', 'ym', 'yn', 'yo', 'yp', 'yq', 'yr', 'ys', 'yt', 'yu', 'yv', 'yw', 'yx', 'yy', 'yz',
 'za', 'zb', 'zc', 'zd', 'ze', 'zf', 'zg', 'zh', 'zi', 'zj', 'zk', 'zl', 'zm', 'zn', 'zo', 'zp', 'zq', 'zr', 'zs', 'zt', 'zu', 'zv', 'zw', 'zx', 'zy', 'zz']

Cool.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • This is a great explanation, actually explaining recursion with a good example. – Avi Nov 07 '10 at 18:03
8

itertools is your friend.

>>> lookup = map(chr, range(32, 127))
>>> import itertools
>>> itertools.permutations(lookup, 10)
<itertools.permutations object at 0x023C8AE0>

Notice that permutations will give you every word, whereas combinations will give you every group of distinct characters. Note also that there are a lot of ten-letter words.

Katriel
  • 120,462
  • 19
  • 136
  • 170
  • Nested loops like the one he has speak more for `product`, don't they? – Björn Pollex Nov 07 '10 at 17:03
  • 1
    @Space: same difference... the cartesian product of a set with *itself* is the same as the set of all 2-combinations of elements of that set. `product` is more general, but that generality is unnecessary here. – Katriel Nov 07 '10 at 17:05
  • What he asked was arrangements, not combinations. – Gabi Purcaru Nov 07 '10 at 17:05
  • @Katrielalex: WOW I loved this, will try this. But my questions is y isn't it printing variables i, j, ... k? – rda3mon Nov 07 '10 at 17:06
  • @Ringo: the code you've given us doesn't have any `print` calls in it, so it's no surprise that it's not printing anything =p if you post the code that's causing a problem, I can look at it. – Katriel Nov 07 '10 at 17:07
  • @Gabi: indeed, fixed (permutation == arrangement). – Katriel Nov 07 '10 at 17:08
  • @Ringo probably because you chose to print one of the outer variables and you didn't wait long enough for the variable to become anything but a blank space. Character 32 is space -- and, for instance, `j` will be a space for the first 692,533,995,824,480,256 lines printed. – hobbs Nov 07 '10 at 17:08
  • `3.66687849 * 10^19` possibilities to be more precise. @katrielalex permutation != arrangement. All permutations of every combination yield the arrangements. – Gabi Purcaru Nov 07 '10 at 17:08
  • Even if I give for k in lookup: print(r) time.sleep(5) It is not working – rda3mon Nov 07 '10 at 17:10
  • @Ringo of course that doesn't work, it makes no sense whatsoever. – hobbs Nov 07 '10 at 17:16
  • @Ringo: works for me; please post the _exact_ (i.e. copy-pasted from the interpreter!) code you have tried. – Katriel Nov 07 '10 at 17:17
  • @hobbs: May be I am trying out something which does not make any sense :) – rda3mon Nov 07 '10 at 17:17
  • 2
    @Gabi: I have never used the word "arrangement" for a combinatorial object but `itertools` (as well as everyone I know) uses "permutation" to mean "ordered list of elements" and "combination" to mean "unordered"> – Katriel Nov 07 '10 at 17:18
  • @katrielalex Permutation = ordered list of **n** elements, and arrangement = ordered list of **k** elements from a set of **n**. This is highschool math. – Gabi Purcaru Nov 07 '10 at 17:19
  • @Gabi: I'm doing university maths and have never heard the word "arrangement". Evidence for my point of view: the button on a calculator for `n!/r!` is `nPr`... but this is a semantic issue anyway =). – Katriel Nov 07 '10 at 17:23
  • @Katrielalex: This is the full code. I started with this and got stuck. – rda3mon Nov 07 '10 at 17:25
  • @Ringo: I just copy-pasted your code into an interpreter and it works. What are you expecting to happen? What OS/Python version are you using? – Katriel Nov 07 '10 at 17:27
  • It is not printing i, j, k, l, m...r inside the loop I am running on eclipse and linux based OS – rda3mon Nov 07 '10 at 17:38
  • @Ringo: try running it in the python shell (open up a terminal, type `python`, and then paste your code). It is possible that eclipse doesn't refresh the screen fast enough, because the amount of data being printed to console is so large. Notice that even doing nothing on each loop iteration would take a ridiculous amount of time (your algorithm is crap, in other words =p) – Katriel Nov 07 '10 at 18:57
1

I've read "Nine Billion Names of God" as well, but I don't think he world will end when your program finishes!

More seriously, Your code is going to be pretty quick and simple. if you put the results in an array (or string), you create an index that pointed to the current level, then for each loop, simply increment the index. When the level is finished, decrement it to "move back". This solution would not be quite as clear, but it would be dynamic - ie. You could choose the number of levels at run time.

winwaed
  • 7,645
  • 6
  • 36
  • 81
  • 1
    I'm not sure if it is a spoiler if it has been in print for 50 or so years. Shall I tell you the ending of Wizard of Oz as well... :-) – winwaed Nov 08 '10 at 02:46
0
import itertools

lookup = map(chr, range(32, 127))

for i in itertools.product(lookup, repeat=10):
    print i

but you will have like (Edit) 96^10 loop so ???

mouad
  • 67,571
  • 18
  • 114
  • 106
  • @ysth : ohhh yes thanks for the correction i was still thinking about 10 char 10 possibility :) – mouad Nov 07 '10 at 17:50