2

I have the following code to test a password for strength:

import string
def golf(password):
    if len(password) >= 10:
        if any(char.isdigit() for char in password):
            if any(string.punctuation for char in password):
                if any(char.isalpha() for char in password):
                    if any(char.isupper() for char in password):
                        if any(char.islower() for char in password):
                            return True
    return False

I know it can be done better! It needs to test for the following ...

The password will be considered strong enough if it has at least 10 characters contains at least one digit contains at least one uppercase letter contains at least one lowercase letter. The password may only contain ASCII Latin letters or digits, but no punctuation symbols.

EDIT

OK for anyone else i got it down to the following with regex.

import re
def golf(password):
    return re.match( r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.{10,30}).+$', password)

Apparently it can still be shorter...

6
  • 2
    Are you not allowed to use and? Commented Jul 19, 2017 at 0:33
  • 2
    if any(string.punctuation for char in password): looks wrong Commented Jul 19, 2017 at 0:34
  • 1
    Have you considered a regex match? Commented Jul 19, 2017 at 0:35
  • 1
    I understand this might just be an exercise, but it you really are using this with people's security, please consider using a library like zxcvbn. It's what they use at DropBox. There's even a Python port github.com/dwolfhub/zxcvbn-python. It's designed specifically to foil pw crackers, which is difficult. Commented Jul 19, 2017 at 0:42
  • If you want to go the regex route that @DavidHoelzer mentions: stackoverflow.com/q/1559751/4996248 Commented Jul 19, 2017 at 0:45

3 Answers 3

3

Actually, you're quite close. Yes, you have a variety of conditions to check; the rules are that complication. Note that you don't have to check for alpha: the checks for islower and isupper cover that. You can make this just a little easier to handle by putting the rules into a single expression:

import string
def golf(password):
    return \
        len(password) >= 10                              and \
        any(char.isdigit() for char in password)         and \
        not any(string.punctuation for char in password) and \
        any(char.isupper() for char in password)         and \
        any(char.islower() for char in password)

Note that you're evaluating a Boolean expression: just return that value. There's no need to say

if <expr>:
    return True
else:
    return False

You already have the value in hand; just return it.

Sign up to request clarification or add additional context in comments.

3 Comments

I think it should be all(char not in string.punctuation
This answer was useful , thanks! I still think it can be done shorter though.. maybe regex?
Yes -- as you found, you can make it shorter with regex. "Better" is a value judgment. I wrote only to improve your existing approach, keeping the simplicity and readability.
0

That's one long string of if statements XD. You should just use some and statements.

if len(password) >= 10 and any(char.isdigit() for char in password)...:
    return True
else:
    return False

The else statement is not necessary, as you know, but it makes the code more readable.

1 Comment

Thanks for that , Yes it is shortened if you use and statements but harder to read also , i believe it can be readable and shorter.
0

The more optimal way would be to do your character checking all in one loop.

import string
def golf(password):
    if len(password) < 10:
      return False

    saw_digit = saw_upper = saw_lower = False
    no_punct = all_alnum = True

    for char in password:
      saw_digit = saw_digit or char.isdigit()
      saw_upper = saw_upper or char.isupper()
      saw_lower = saw_lower or char.islower()
      no_punct = no_punct and (char not in string.punctuation)
      all_alnum = all_alnum and char.isalnum()

    values = [saw_digit, saw_lower, saw_upper, no_punct, all_alnum]
    # print(values)
    return all(values)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.