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...
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.
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.
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)
Related
I want to know that 'password' is containd number using 'string.digits'
import string
def validate_password(password):
is_long = len(password)
if is_long < 8:
return False
includes_digit = password
for digit in string.digits:
if digit in includes_digit:
break
return False
for u in string.ascii_uppercase:
if u in includes_digit:
break
return False
for char in string.ascii_lowercase:
if char in password:
break
return False
return True
is_password_valid = validate_password("12345678ff")
print(is_password_valid)
I guess that is ok but didn't work
help me plz
In all of your validators, you don't return False because that return statement is underneath the if statement. You always break before reaching the return.
Put an else under your for loops like this. This part executes if the for loop finishes without encountering a break.
includes_digit = password
for digit in string.digits:
if digit in includes_digit:
break
else:
return False
You should use regex in this case.
import re
password = 'Azerty123'
contains_digit = bool(re.search('\d', password))
print(contains_digit) # True
As part of an assignment, I'm creating a program to ask a user to input a username and password.
I've completed the username part (easy), but in the assignment instructions, the password must:
contain an uppercase character
contain a lowercase character
be longer than 6 characters
contain a number
have no white space
There are 5 specific error messages that need to display if any of these conditions are not true.
What I've got currently has some weird behavior, the errors only show up in a specific order (for example, password "f" will have the error "must have an uppercase character" instead of "must be longer than 6 characters"). I know this is because of the nesting order of the if statements, but if there's a better way... It also for some reason doesn't catch white space in the password. I know it probably isn't the most efficient way but here's what I've got so far:
def validatePassword():
accept = "n"
while accept == "n":
password = input("Please enter a valid password: ")
upper = "n"
lower = "n"
digit = "n"
length = "n"
white = "n"
if len(password) >= 6:
length = "y"
for char in password:
if char in string.ascii_uppercase:
upper = "y"
if char in string.ascii_lowercase:
lower = "y"
if char in string.digits:
digit = "y"
if char not in string.whitespace:
white = "y"
if upper == "y":
if lower == "y":
if digit == "y":
if length == "y":
if white == "y":
accept = "y"
else:
print("::: ERROR :::",password,"must not have any white space character.")
else:
print("::: ERROR :::",password,"must be longer than 6 characters.")
else:
print("::: ERROR :::",password,"must contain a number.")
else:
print("::: ERROR :::",password,"must contain a lowercase character.")
else:
print("::: ERROR :::",password,"must contain an uppercase character.")
return password
You could try something like this:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def validatePassword(password):
if not any(x.isupper() for x in password):
return False, "No upper case character"
if not any(x.islower() for x in password):
return False, "No lower case character"
if len(password) < 6:
return False, "Not longer than 6 characters"
if not any(x.isdigit() for x in password):
return False, "No number"
if any(x.isspace() for x in password):
return False, "Contains hitespace"
return True, ""
def test():
# test some passwords
test_passwords = ["lkjasdf", "KAJSDF", "lfSF", "asdfADSF", "asdf ADSF 123", "asdfADSF123"]
for p in test_passwords:
print validatePassword(p)
# "real" usage
while True:
password = input("Please enter a valid password: ")
result, message = validatePassword(password)
if result is True:
break
else:
print(message)
if __name__ == '__main__':
test()
Obviously the correct way to do this is with any() and a generator expression, but seeing as how you said I'm like 8 weeks into a 10 week introductory course those probably don't help you.
Here's how you can do it without using any() by just looping through the characters checking for the presence of certain types of characters.
def validate_password(password):
hasUpper = hasLower = hasNumber = hasWhiteSpace = False
for char in passwordStr:
if char.isupper():
hasUpper = True
if char.islower():
hasLower = True
if char.isdigit():
hasNumber = True
if char.isspace():
hasWhiteSpace = True
if len(password) <= 6:
return False, "Password must be longer than 6 characters"
if not hasUpper:
return False, "Password must contain atleast one uppercase character"
if not hasLower:
return False, "Password must contain atleast one lowercase letter"
if not hasNumber:
return False, "Password must contain alteast one number"
if hasWhiteSpace:
return False, "Password cannot contain any white space"
return True
First, there's the data type bool which can represent the values True and False. You should use them to represent simple true/false states instead of assigning the strings "y" and "n".
Second, checking every character separately and storing whether the different conditions are met at least once is a possible way. However, Python has powerful string examination methods that can make your life much easier. Let me demonstrate them by writing a short function which takes aa password as argument and simply returns True or False depending on whether the passwords meets your restrictions:
def is_password_valid(password):
# check password length:
if len(password) < 6:
print("Your password is too short, at least 6 characters are required!")
return False
# check if password contains any non-alphanumeric letters (including whitespace):
# (isalnum() only returns true if the string only contains letters and digits, nothing else)
if not password.isalnum():
print("Your password may only contain letters and digits!")
return False
# check if password contains letters:
# (isdigit() only returns true if all of the characters are numbers)
if password.isdigit():
print("Your password does not contain any letters!")
return False
# check if password contains uppercase letters:
# (islower() only returns true if all of the letters are lowercase, non-letters are ignored)
if password.islower():
print("Your password does not contain any uppercase letters!")
return False
# check if password contains lowercase letters:
# (isupper() only returns true if all of the letters are uppercase, non-letters are ignored)
if password.isupper():
print("Your password does not contain any lowercase letters!")
return False
# check if password contains lowercase numbers:
# (isalpha() only returns true if all of the characters are letters)
if password.isalpha():
print("Your password does not contain any numbers!")
# if all conditions above are okay, the password is valid:
print("The password is okay.")
return True
You may of course reorder the blocks in my code above as you wish.
You can then simply use this helper function inside your loop which looks a lot simpler and cleaner now:
def validate_password():
accept = False
while not accept:
password = input("Please enter a valid password: ")
accept = is_password_valid(password)
You can try Regular Expressions. If you don't know about regex, as you've mentioned in your comment, this is a great website.
For validation, check if the password matches with any of the rules which will render it invalid and if not, it is a valid password.
import re
def validate(passwd):
pattern = r'^(.{0,5}|[^0-9]*|[^A-Z]*|[^a-z]*|.*\s+.*)$'
result = re.search(pattern, passwd)
if result:
print 'Invalid Password'
else:
print 'Valid Password'
What this does is check if, passwd is less than 6 chars OR contains no numbers OR contains no uppercase chars OR contains no lowercase chars OR contains spaces. If none of the criteria matches, the password is valid.
I'm working on an exercise problem from the regex chapter in 'Automate the boring stuff with Python' the question and my code is below. I got the regex working in the Python shell and I think its correct but I just can't get it to work within my function so that it returns the correct answer.
Write a function that uses regular expressions to make sure the password string it is passed is strong. A strong password is defined as one that is at least eight characters long, contains both uppercase and lowercase characters, and has at least one digit. You may need to test the string against multiple regex patterns to validate its strength.
import re
def pwRegex():
print "Please enter a password"
user_pw = raw_input("> ")
#your_pw = str(user_pw)
passGex = re.compile(r'^(?=.*\d)(?=.*[A-Z])\w{8,15}$')
pass_w = passGex.search(user_pw)
if pass_w != '':
print "Well done"
else:
print "Try again"
pwRegex()
the output I get is "Try again" every time even when I'm entering a password that should pass the regex. I tried making the if statement pass_w == True: but then everything that I entered seemed to pass the regex even if incorrect.
Regex searching in python gives back a MatchObject, not a string. If it does not find the required pattern, it will return None. You should check for None, or, more pythonically, check for truthiness
# if pass_w != None: # => less pythonic
if pass_w:
print 'Well done'
else:
print 'Try again'
import re
print('Please set a new password: ')
def strongpassword():
while True:
password = input()
if lowcase.search(password) == None:
print('The entered password doesn\'t have a lower case character')
continue
if upcase.search(password) == None:
print('The entered password doesn\'t have an upper case character')
continue
if digit.search(password) == None:
print('The entered password doesn\'t have a digit')
continue
if space_8.search(password) == None:
print('The entered password should have atleast 8 characters and no space in between')
continue
else:
print('New Password is Valid and Saved')
break
lowcase = re.compile(r'[a-z]') # this regex searches for atleast one lower case alphabet
upcase = re.compile(r'[A-Z]') # this regex searches for atleast one upper case alphabet
digit = re.compile(r'(\d)') # this regex searches for atleast one digit
space_8 = re.compile(r'^[a-zA-Z0-9]{8,}$') # this regex searches for expressions without any space and atleast 8 characters
strongpassword()
I guess, it is not relevant anymore. However, I would like to suggest this:
import re
pasword = re.compile(r'''(
\d+ #have at lest one digit
.* # anything
[A-Z]+ # at least 1 capital
.*
[a-z]+ # at least one lower
.*
)''', re.VERBOSE)
# test
pasword.search('1##A!a').group()
def is_strong_password():
pas = input('Enter a password:')
if len(pas) < 8:
return False
else:
check = pasword.search(''.join(sorted(pas))).group() #sorted is important to be sure that user can write symbols in any order he/she wants
if (not check):
print('Not strong pasword')
return False
else:
print('Strong password')
return True
I was also working on the same exercise, I'm learning python as well. You can search() instead of findall(). i just used it just to test it out.
import re
print('Enter new password')
def strongPW():
while True:
pw = input()
lowercase = [] # lowercase
uppercase = [] # uppercase
digit = [] # number
if len(pw) < 8:
print('your password must have 8 characters or more')
break
# lowercase verification
pwRegex = re.compile(r'[a-z]')
lowercase = pwRegex.search(pw)
if lowercase == []:
print('Your password must have at least one lowercase')
break
# uppercase verification
uppercaseRegex = re.compile(r'[A-Z]')
uppercase = uppercaseRegex.findall(pw)
if uppercase == []:
print('Your password must have at least one uppercase')
break
# digit verification
DigitRegex = re.compile(r'[0-9]')
digit = DigitRegex.findall(pw)
if digit == []:
print('Your password must have at least one digit')
break
else:
print('Your password meets all requirements ')
break
strongPW()
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.
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.
you are just missing a branch
elif note:
return False
before the else:
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! ")
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
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.
I'm trying to make a password with typical requirements like it has at least 1 uppercase/lowercase, etc. If the password is not valid according to the requirements, we have to display the errors in order for the user to try to get it correct again.
I started out with a while loop so that in the end the user will have an option to continue with another test or not. These are general steps I did.
At the end, if the user's text input is determined to not be valid, I have to display what his/her errors were. That's my main problem now. The code is better after a suggestion. Now I just have to display the errors somehow.
Here's how my code went
while True:
pw = input('Enter password to be tested if valid or not: ')
correct_length = False
uc_letter = False
lc_letter = False
digit = False
no_blanks = True
first_letter = False
if len(pw) >= 8:
correct_length = True
for ch in pw:
if ch.isupper():
uc_letter = True
if ch.islower():
lc_letter = True
if pw.isalnum():
digit = True
if pw[:1].isalpha():
first_letter = True
if not pw.find(' '):
no_blanks = True
if correct_length and uc_letter and lc_letter and digit and first_letter and no_blanks:
valid_pw = True
else:
valid_pw = False
#This is the part where I'm suppose to display the errors if the user gets it wrong.
#Initially, in the test for ch. above, I put in an else: with a print statement but because of the for- statement, it prints it out for every single character.
answer = input('Try another password input? y/n ')
if answer == 'y'
answer = True
else:
break
isdigit only returns True or False.
if ch.isdigit():
If you want to check if the first two characters are digits, do it outside the loop:
if pw[:2].isdigit():
digit = True
for ch in pw:
...
And to check if there are spaces in the string:
if not pw.find(' '):
no_blanks = True
Or if you want to escape all kinds of white spaces and blanks, including newline characters:
import string
...
if not any(c in string.whitespace for c in pw):
no_blanks = True
for ch in pw:
...
For the white space I would use (don't forget to import string):
import string
for ws in string.whitespace:
if ws in pw:
no_blanks = False
break
This checks for all kinds of white space, including for example Space and Tab
For the digits I would define dig_count = 0 before your for-loop.
Inside the for-loop:
if ch.isdigit():
dig_count += 1
After the for-loop:
if dig_count >= 2:
digit = True