Reputation: 35
I need some help figuring out how to make a function that checks a string for a bunch of conditions.
Passwords must be at least 5 characters long
Passwords must contain at least one upper case letter
Passwords must contain at least two numbers
Passwords may not contain the characters "E" or "e"
Passwords must include at least one special symbol: !, @, #, $, %, ^, &
right now this is all that I have
def passwordChecker(password):
'''
'''
caps = sum(1 for c in password if c.isupper())
nums = sum(1 for c in password if c.isdigit())
symb = any(c in password for c in '!@#$%^&')
note = any(c in password for c in 'Ee')
if len(password) <5:
return False
elif caps < 1:
return False
elif nums < 1:
return False
elif symb == False:
return False
else:
return True
Edit**
Just realized that I have to check also if there are commonly used passwords like 'password' or '111111' and I dont really know about how I would approach this.
Upvotes: 2
Views: 2462
Reputation: 6607
Yet another way to do this...
def passwordChecker(password):
return (len(password) > 4 and
len(filter(str.isupper, password)) > 0 and
len(filter(str.isdigit, password)) > 1 and
'e' not in password.lower() and
any(special in password for special in '!@#$%^&') and
password not in ('password', '111111'))
I think the most interesting part of my solution is the use of filter
; some people like it, others hate it. Anyway, all of the other solutions work just as well. Just thought I'd throw this one into the mix for completeness.
Upvotes: 0
Reputation: 54223
This is a good time to talk about decorators! I love using decorators to validate data, probably too much. You could make validators for all that, and wrap it around your get_password
method.
def v_length(password):
return len(password) >= 5
def v_upper(password):
return password.lower() != password
def v_2_nums(password):
return sum(c.isdigit() for c in password) >= 2
def v_no_e(password):
return "e" not in password.lower()
def v_specialchar(password):
any(s in password for s in "!@#$%^&")
def validator(*tests):
def wrap(func):
def wrapped(*args, **kwargs):
result = func(*args, **kwargs)
if not all(test(result) for test in tests):
# fail the input somehow -- how??
return result
return wrapped
return wrap
@validator(v_length, v_upper, v_2_nums, v_no_e, v_specialchar)
def get_password():
pwd = input("Enter your password: ")
I like to wrap my validators in their own factories when I do this in real code, so that it's easier to change per application
def v_length(min_length):
def wrapped(password):
return len(password) >= min_length
return wrapped
@validator(v_length(8))
def get_weak_password():
input("Enter your wussy password: ")
@validator(v_length(64))
def get_strong_password():
input("Enter your Herculean password: ")
This second approach works well for checking for common passwords.
def v_common(common_pwd_set):
def wrapped(password):
return password not in common_pwd_set
return wrapped
COMMON_PASSWORDS = {"hunter2", "111111", "password"}
@validator(v_common(COMMON_PASSWORDS))
def get_password():
pwd = input("Use a tricksy one! ")
Upvotes: 1
Reputation: 28656
Just an alternative using regular expressions:
import re
def passwordChecker(password):
return all(re.search(pattern, password) for pattern in
('.{5}', '[A-Z]', '\d.*\d', '^[^Ee]*$', '[!@#$%^&]'))
Demo using five barely invalid and five barely valid tests (one invalid and one valid for each of the five rules):
for password in ('1A!', '12!34', 'A1bc!', 'A12E!', 'A12bc',
'1A!2.', 'A2!34', 'A12c!', 'A12b!', 'A12b@'):
print(passwordChecker(password))
Prints False
for the first five and True
for the last five.
Upvotes: 2
Reputation: 49330
The following checks for each failure condition, with short-circuiting (it'll stop checking once it finds something). The "common" passwords aren't really common, but I wanted values that would pass the rest of the checks.
def passwordChecker(password):
'''
A password checker. Returns True if the password is acceptable; False otherwise.
'''
if (len(password) < 5 or
not any(c.isupper() for c in password) or
sum(c.isdigit() for c in password) < 2 or
'e' in password.lower() or
not (set(password) & set('!@#$%^&')) or
password in {'Password12!', 'Passwd12!'}):
return False
return True
>>> passwordChecker('Password12!')
False
>>> passwordChecker('hi')
False
>>> passwordChecker('H12!')
False
>>> passwordChecker('Hi12!')
True
Upvotes: 0
Reputation: 18950
you are just missing a branch
elif note:
return False
before the else:
Upvotes: 1