1

Breaking out of a for loop

My code will not break out of the loop:

(I truncated some parts that were for cosmetics)

lchars = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '!', '@', '\\', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', '_', '+', '`', '~', '[', ']', '{', '}', '|', ';', ':', "'", ',', '.', '/', '<', '>', '?', '`', '¡', '™', '£', '¢', '∞', '§', '¶', '•', 'ª', 'º', '–', '≠', 'œ', '∑','´', '®', '†', '¥', '¨', 'ˆ', 'ø', 'π', '“', '‘', '«', 'å', 'ß', '∆', '˚', '¬', '…', '˜', 'µ', '≤', '≥', '÷', 'æ', 'Ω', '≈', 'ç', '√', '"', ' ']


guessThisPass = str(input("Enter the password you want the python-based brute force hacker to guess (Character limit is 4): "))
if len(guessThisPass) > 4:
    print('I SAID CHARACTER LIMIT IS 4!! I AM TRUNCATING YOUR PASSWORD NOW! ')
    guessThisPass[0:4]
    time.sleep(5)
print("Starting...")
time.sleep(2)
start = time.time()
for d in lchars:
    for c in lchars:
        for b in lchars:
            for a in lchars:
                tryPass = str(str(a) + str(b) + str(c) + str(d)). # I know the strs are probably unnessecary.
                print(tryPass). # Outputing the attempted password
                if tryPass == guessThisPass:
                    break # This never happens

print("Whoo!")
print("That took ", time.time()-start, "seconds.")

Using this code, let's say my password was 'a' (which IRL, it is not). Then, logically, it should be able to break out of it almost instantly, right? Except it doesn't; it just keeps on going, not breaking, even up to the combination '^Bc' or higher. Why does it not break? Do I need to add the if statement in every single one of the loops?

Tester code

Also, here is the code I used to test the possible combinations:

(Also truncated redundant cosmetics)

# All possible combinations
lchars = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '!', '@', '\\', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', '_', '+', '`', '~', '[', ']', '{', '}', '|', ';', ':', "'", ',', '.', '/', '<', '>', '?', '`', '¡', '™', '£', '¢', '∞', '§', '¶', '•', 'ª', 'º', '–', '≠', 'œ', '∑','´', '®', '†', '¥', '¨', 'ˆ', 'ø', 'π', '“', '‘', '«', 'å', 'ß', '∆', '˚', '¬', '…', '˜', 'µ', '≤', '≥', '÷', 'æ', 'Ω', '≈', 'ç', '√', '"', ' ']
# print("Also, there are ", len(lchars), "characters in our character database\n\n")
from time import time
start = time()
for d in lchars:
    for c in lchars:
        for b in lchars:
            for a in lchars:
                print(a+b+c+d)
print("Whoo!")
print("That took ", time()-start, "seconds.")

I checked the output of the above code. The letter 'a' was in the output. It should work. Why is it not working?

theX
  • 1,008
  • 7
  • 22
  • 3
    the `break` breaks only from the most inner loop, in this case `for a in lchars:`. You probably want to put all the loops inside function and use `return` instead of `break`. – Andrej Kesely May 31 '20 at 22:17
  • 5
    Look into `itertools.product()` rather than a 4-levels deep nested loop. As an added advantage, you could have a 1-level deep nested loop for which `break` would work. As another advantage, it wouldn't hard-wire in the length of 4. – John Coleman May 31 '20 at 22:19
  • 1
    See [this post](https://stackoverflow.com/questions/189645/how-to-break-out-of-multiple-loops). – Cleb May 31 '20 at 22:19

3 Answers3

3

It is breaking. The problem is, break only breaks from the inner loop; not every loop that contains it. The inner-most loops breaks, then the loop that surrounds it picks up where it left off.

Without changing your code too much, the simplest solution would be to wrap that code in a function and return from it:

def try_all(lchars):
    for d in lchars:
        for c in lchars:
            for b in lchars:
                for a in lchars:
                    tryPass = a + b + c + d
                    print(tryPass)
                    if tryPass == guessThisPass:
                        return tryPass

cracked_password = try_all(lchars)

There are many other improvements that should be touched on, but that isn't appropriate here. Once you get the code working and complete, you can post it on Code Review for general suggestions.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • 1
    So, `return` would break out of the entire function, right? I see... Thanks! – theX May 31 '20 at 22:31
  • Yes. `return` causes you to unconditionally exit the function; regardless of what you're nested in. I'm using that here to exit all loops at once. With the nested loops that you have, that's really the only simple option. An `itertool` function like Asocia mentions would be the much cleaner option (since then you won't have nested loops at all), but requires reconfiguring your code a bit. – Carcigenicate May 31 '20 at 22:33
2

Actually it does break but since you have 4 nested loops, it just breaks the innermost loop. You can do several things to solve this:

  • Create a flag and check it before continueing
  • Move your code into a function and return when you find an answer
  • Use itertools.product to create your trial strings. This way you will need only one loop so breaking will be simple.
Asocia
  • 5,935
  • 2
  • 21
  • 46
1

Yes, break will only get you out of the inner-most loop! I would move that code into a function, which can return tryPass when it finds the right one.

Happy Coding!

Sam
  • 1,406
  • 1
  • 8
  • 11