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.
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
This is my code which and it asks a user to enter a password string and checks for any repeated elements.The thing is I didn't understand the code and why they set a unique_element to an empty string.And what does unique+=password[i] do,why is i in [] in this brackets?
def check_pass():
password= raw_input('Enter a password:')
unique_element = ''
for i in range (len(password)):
if len(unique_element) == 0:
unique_element += password [i]
else:
not_unique = True
for j in range (len(unique_element)):
if unique_element[j] == password[i]:
not_unique = False
if not_unique:
unique_element += password[i]
return unique_element == password
print check_pass()
Explaining the Code above may be a little tedious. Suffice it to say that if your intention is to check if a given String [password] contains any duplicate character, you might do that without the need for any loops - which (in this case) is likely unnecessary. Here's how:
def pass_has_unique_characters():
# CAPTURE THE ENTERED CHARACTERS
password = input('Enter a password:')
# SETS CANNOT HAVE DUPLICATES SO WE CAST THE STRING (password) TO A SET
st_password = set(password)
# NOW WE CHECK THE LENGTHS OF BOTH: password AND st_password
# IF BOTH HAVE THE SAME LENGTH, THEN THE PASS HAS UNIQUE CHARACTERS,
# RETURN [True] ... OTHERWISE RETURN [False]
return (True if len(st_password) == len(password) else False)
print(pass_has_unique_characters())
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)
This question already has an answer here:
Variable checking, something not right
(1 answer)
Closed 6 years ago.
I have tried to make a 'password checker' program that checks if an entered variable contains specific characters. I will need it to check thee things: uppercase, lowercase and number.
There are 3 things that the program will hopefully output, and these are:
Weak, for passwords with only upper OR only lower OR only number
Medium, for passwords that have upper and lower, OR upper and number, OR lower and number
Strong, for passwords that contain upper, lower and number at the same time.
This is my code:
if EnteredPassword.isupper() or EnteredPassword.islower() or EnteredPassword.isdigit():
print ("Your password is weak")
elif EnteredPassword.isupper()and EnteredPassword.islower():
print ("Your password is medium")
elif EnteredPassword.isupper() and EnteredPassword.isdigit():
print ("Your password is medium")
elif EnteredPassword.islower() and EnteredPassword.isdigit():
print ("Your password is medium")
elif EnteredPassword.isupper() and EnteredPassword.islower() and EnteredPassword.isdigit():
print ("Your password is strong")
else:
print ("That password should not have been accepted")
quit()
However, when the program is run, and for example I have put in UPPERLOWER6 the program skips to the else statement. If I put something that just contains UPPER etc., that is the only one that works and comes up with your password is weak
If there is anything wrong with the code I cannot see, please point it out. I have been re-directed to other questions but they are too complicated for me and people would know I have copied is, which is not allowed.
Many thanks!
you should do something like this:
Password Tester in Python
the functions you are using test the whole string and to make what you want to do is not the right option.
Use regex. Its easier.
Your code isn't working the way you want it to because isupper, islower and isdigit all check all the values of the string you feed it. i.e. 'a'.islower() returns True, while 'aA'.is lower() returns False.
So,
if str.isupper() and str.islower():
#statement
is never executed because one of the conditions is always bound to be False.
Note: isupper and islower ignore any digits if any character is present in the string. i.e. 'a6'.islower() return True, while '6'.islower() and 'a6'.isdigit() return False.
isupper / islower is not working same as like isdigit.
upper and lower ignores any digits and whitespaces (eg "UPPER6 ".isupper() is True)
on the other way digit check if string contains only digits
Anyway 'UPPERLOWER6' matches first condition, so it shouldn't skip to else. You string probably contains something else.
You can still iterate over chars, eg:
flags = [False] * 3
for ch in EnteredPassword:
flags[0] = flags[0] or ch.islower()
flags[1] = flags[1] or ch.isupper()
flags[2] = flags[2] or ch.isdigit()
strength = sum(flags)
print("Your password is {}".format(
["not accepted", "weak", "medium", "strong"][strength])
)
You r doing it wrong way as you can use isupper or islower functions only on characters and not on whole string. I would do something like this:
def containsOnlyUpper(s):
for c in s:
if(not c.isupper()):
return False
return True
def containsOnlyLower(s):
for c in s:
if(not c.islower()):
return False
return True
def containsOnlyNumber(s):
for c in s:
if(not c.isdigit()):
return False
return True
def containsUpperAndLower(s):
hasUpper = False
hasLower = False
for c in s:
if (c.islower()):
hasLower = True
if (c.isupper()):
hasUpper = True
if(hasUpper and hasLower):
return True
else:
return False
def containsUpperAndNumber(s):
hasUpper = False
hasNumber = False
for c in s:
if (c.isupper()):
hasUpper = True
if (c.isdigit()):
hasNumber = True
if(hasUpper and hasNumber):
return True
else:
return False
def containsLowerAndNumber(s):
hasLower = False
hasNumber = False
for c in s:
if (c.islower()):
hasLower = True
if (c.isdigit()):
hasNumber = True
if(hasLower and hasNumber):
return True
else:
return False
def isWeakPassword(s):
if(containsOnlyUpper(s) or containsOnlyLower(s) or containsOnlyNumber(s)):
return True
return False
def isMediumPassword(s):
if(containsUpperAndLower(s) or containsUpperAndNumber(s) or containsLowerAndNumber(s)):
return True
return False
def isStrongPassword(s):
hasUpper = False
hasLower = False
hasNumber = False
for c in s:
if (c.isupper()):
hasUpper = True
if (c.islower()):
hasLower = True
if (c.isdigit()):
hasNumber = True
if (hasLower and hasUpper and hasNumber):
return True
else:
return False
password = "UPPERLOWER6"
if(isWeakPassword(password)):
print "weak"
elif(isMediumPassword(password)):
print "medium"
elif(isStrongPassword(password)):
print "strong"
else:
print "none"
I think you could set variables as flags, then check the letter and recording the number of occurrences in input one by one.
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.