patternpythonMinor
Regex password strength test
Viewed 0 times
regexteststrengthpassword
Problem
I've been following a Python programming book and reached the Regex chapter where I encountered this challenge:
Write a password strength checker that checks if a password is:
I managed to do so, but frankly my solution seems both long and ugly. I was hoping someone could shed some light as to how I could maybe condense my program and improve readability if possible.
And here is my non-regex solution if you can't read the above and want to see what I am trying to do with regex:
I know this isn't a good test of password strength, but it was the book's challenge. I'm not implementing it for any real use.
Write a password strength checker that checks if a password is:
- At least 8 character long
- Contains at least one uppercase and lowercase letter.
- And contains at least one digit.
I managed to do so, but frankly my solution seems both long and ugly. I was hoping someone could shed some light as to how I could maybe condense my program and improve readability if possible.
import re
def is_password_strong():
password = input('Enter a password to test: ')
length_regex = re.compile(r'.{8,}')
length = True if length_regex.search(password) != None else False
uppercase_regex = re.compile(r'[A-Z]')
lowercase_regex = re.compile(r'[a-z]')
uppercase = True if uppercase_regex.search(password) != None else False
lowercase = True if lowercase_regex.search(password) != None else False
case = True if uppercase and lowercase == True else False
digit_regex = re.compile(r'[0-9]')
digit = True if digit_regex.search(password) != None else False
return(length and case and digit == True)
print(is_password_strong())And here is my non-regex solution if you can't read the above and want to see what I am trying to do with regex:
def is_password_strong():
password = input('Enter a password to test: ')
length = len(password) >= 8
case = password != password.upper() and password != password.lower()
digit = any(c.isdigit() for c in password)
return(length and case and digit == True)I know this isn't a good test of password strength, but it was the book's challenge. I'm not implementing it for any real use.
Solution
Here are the major comments:
-
Ideally functions should do one thing at once. Your function is doing two: (1) asking the user for a password and (2) evaluating the strength of that password.
You should break this code into two functions: (1)
-
Regexes are not always the right tool for the job. (I appreciate this is a chapter on regexes, but the point has to be made.)
Python has fairly powerful string manipulation tools. You should reach for those before opening your regex toolbox – I think the Python constructs are usually much easier to read and debug. Brownie points for writing a version that doesn’t use regexes – I would almost always prefer this version in a “real” codebase.
-
Be lazy about evaluation. This function is fairly fast, because it doesn’t have many checks. Even so, you can save yourself a little work – as soon as a check fails, you can return False.
(It’s fine to bail out early for a password strength evaluation. Try to avoid doing this when doing real authentication – if your function takes noticeably different time depending on what’s wrong with the function, you’re vulnerable to a timing attack.)
-
Your function should have a docstring. Docstrings are the preferred way to document functions in Python. For this function, it should be fairly simple -- it evaluates a password, and returns True/False depending on whether it meets certain criteria -- but you should still write it.
And a few nitpicks:
-
Compare to None with “is”, not “==” and “!=”.
It’s always preferred to check using “is”, which checks identity, not equality – this makes sure the object you’re dealing with really is None, and not a class with a strange equality operator. It’s also faster.
-
You can tidy up your booleans.
Quite a few of your lines boil down to:
This line reduces to:
That’s more readable and direct.
Then your final boolean can be reduced to:
which is equivalent.
-
Put your main code in an
This makes your code easier to reuse.
-
Ideally functions should do one thing at once. Your function is doing two: (1) asking the user for a password and (2) evaluating the strength of that password.
You should break this code into two functions: (1)
ask_user_for_password() and (2) is_password_strong(password).-
Regexes are not always the right tool for the job. (I appreciate this is a chapter on regexes, but the point has to be made.)
Python has fairly powerful string manipulation tools. You should reach for those before opening your regex toolbox – I think the Python constructs are usually much easier to read and debug. Brownie points for writing a version that doesn’t use regexes – I would almost always prefer this version in a “real” codebase.
-
Be lazy about evaluation. This function is fairly fast, because it doesn’t have many checks. Even so, you can save yourself a little work – as soon as a check fails, you can return False.
(It’s fine to bail out early for a password strength evaluation. Try to avoid doing this when doing real authentication – if your function takes noticeably different time depending on what’s wrong with the function, you’re vulnerable to a timing attack.)
-
Your function should have a docstring. Docstrings are the preferred way to document functions in Python. For this function, it should be fairly simple -- it evaluates a password, and returns True/False depending on whether it meets certain criteria -- but you should still write it.
And a few nitpicks:
-
Compare to None with “is”, not “==” and “!=”.
It’s always preferred to check using “is”, which checks identity, not equality – this makes sure the object you’re dealing with really is None, and not a class with a strange equality operator. It’s also faster.
-
You can tidy up your booleans.
Quite a few of your lines boil down to:
result = True if (check != None) else FalseThis line reduces to:
result = (check is not None)That’s more readable and direct.
Then your final boolean can be reduced to:
return (length and case and digit)which is equivalent.
-
Put your main code in an
if __name__ == '__main__' block. This means that it only runs when the file is called directly – not, for example, when it’s imported as a module.This makes your code easier to reuse.
Code Snippets
result = True if (check != None) else Falseresult = (check is not None)return (length and case and digit)Context
StackExchange Code Review Q#112404, answer score: 8
Revisions (0)
No revisions yet.