checking if string has two or more uppercases - python

I'm writing a function that checks multiple conditions for a string (a "password"). This string has to be between 6 and 20 characters long, must have at least one number, must have special characters AND must have at least two uppercase letters.
This is where I ran into problems because I'm using RegEx and I can't get the "must have two uppercase letters" part to work, everything else works fine.
import re
password = input("Input password: ")
def valid_pw(password):
valid = True
if not re.search(',{6,20}', password):
valid = False
if not re.search('[0-9]', password):
valid = False
if not re.search('[A-Z].*[A-Z]', password):
valid = False
if not re.search('[$&+,:;=?##|<>.^*()%!-]', password):
valid = False
return valid
print(password, "is valid: ", valid_pw(password))
The third "if" statement is my attempt at checking for two uppercase letters but doesn't work as expected. If the input is password: AbC.123 the output should be "AbC.123 is valid: True" since it checks every condition, yet I'm still getting "False" due to the two uppercase part.

None of your checks require regular expressions to implement.
def valid_pw(password):
if not 6 <= len(password) <= 20:
return False
if not any(c.isdigit() for c in password):
return False
if sum(c.isupper() for c in password) < 2:
return False
if not any(c in '[$&+,:;=?##|<>.^*()%!-]' for c in password):
return False
return True
Notice that once any of the conditions returns False, you can stop searching: the password won't become true after that.
In your original formulation, elif would be preferable to if for all the latter clauses. Also, the symbol . means "any character", not ,. Your checks were likely failing due to that, and not the capitalization check. You may have failed to realize that because all the checks were running instead of terminating early.

A slight improvement to your code snippet would be to start with a 'false' and then check for each condition consequently and finally set the valid to 'true'. You can use regex search for special characters and numbers.
Use len() for checking the length parameter, and in a loop (one liner is good) check for upper case in the string (ie looping through every character of the string).
Working code below.
import re
password_str = "Abc#123"
def validate_pw(pwd):
valid = False
if len(pwd) > 6 & len(pwd) <= 20:
if re.search(r'\d', pwd):
regexp = re.compile('[^0-9a-zA-Z]+')
if regexp.search(pwd):
if (any(x.isupper() for x in pwd)):
valid = True
print(valid)
validate_pw(password_str)

Related

How can I make the output return True if everything in the criteria is met?

So I wrote this code originally for passwordlength(password) to find whether these criterias are met or not...
def passwordlength(password: str):
upper = digit = special = False
for char in password:
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and "1234567890" and "abcdefghijklmnopqrstuvwxyz":
upper = True
if char in "1234567890":
digit = True
if char in "$##%!":
special = True
if upper and digit and special:
return True
return False
and now I created a new function to find whether the length of the string is within 6 to 12 characters AND whether each element in the string appears lesser than 3 times or not.. and here it is
def passwordOK(password: str):
if passwordlength(password)== True:
if len(password) > 6 and len(password) < 12:
return True
for char in password:
if password.count(char) <= 3:
return True
else:
return False
if passwordlength(password) == False:
return False
print(passwordOK(password='aaaa1jd4kjfs$jDhfksfd'))
When I tried to run this, it didn't work at all.. Can someone please help me find the error and correct me? Thank You:)
The following would resemble some workable logic and code:
def passwordlength(password: str):
upper = digit = special = False
for char in password:
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
upper = True
elif char in "1234567890":
digit = True
elif char in "$##%!":
special = True
return upper and digit and special
def passwordOK(password: str):
if passwordlength(password):
if not (6 < len(password) < 12):
return False # return False early
for char in password:
if password.count(char) > 3:
return False # again: return False early
return True # only when all chars have been checked, you know it's ok
return False
Of course the naming is still weird. If I were to redo it:
from collections import Counter
from string import ascii_uppercase, digits, punctuation
def characterclass_check(password: str):
for char_class in (ascii_uppercase, digits, punctuation):
if not any(c in char_class for c in password):
return False
return True
def passwordOK(password: str):
if not characterclass_check(password):
return False
if not (6 < len(password) < 12):
return False
return max(Counter(password).values()) <= 3
There are many problems with this code.
First
if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and "1234567890" and "abcdefghijklmnopqrstuvwxyz"
will be evaluated as
if (char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ") and ("1234567890") and ("abcdefghijklmnopqrstuvwxyz")
thus only checking if the character is uppercase, as the other strings will evaluate to True simply by having content. The variable name you're setting is upper, so I'm not sure why those other strings are there to start with - they're not what you're trying to check against.
Second, you unnecessarily call passwordlength(password) twice when the second one could (and should) be an else.
Third, you return immediately on checking the password length in passwordOK, so if it's between 6 and 12 characters you never check for duplicate characters.
Fourth, when you check for duplicate characters you return as soon as you find one that appears less than 4 times, meaning that "aaaaaabbbbbbcdddddd" would pass. I assume this was not your intention.
Fifth, your else on the for loop is unnecessary as in your case it will always run if you don't return from within the loop. It's only useful if you have a break.
Sixth, you have a function named passwordlength that doesn't actually check the length of the password.
I may have missed other issues.

Creating basic Python function to test if string password meets length requirements and contains special characters and digits

I am a beginner in Python (using python3), and just learning to write basic functions. I am trying to solve the following problem: Write a function that takes a string as input and it returns whether the string is a valid password (the return value is True) or not (the return value is False). A string is a valid password if it:
contains least 1 number between 0 and 9, and
contains at least 1 character from the list ['$','#','#','.','!','?','<','>'] and
has a minimum length of at least 6 characters.
As you can see below I wrote three very basic functions which address the three conditions above separately. I understand that there are more advanced functions such as regex that would take care of this, but would like to stick to the basics.
I would like to create a fourth function which runs the list of passwords through this functions and then determines whether the string is valid or not. I am unable to create this function properly and would really appreciate some help. Thanks!
passwords_lst = ['ilikeplums!','plum2020','a2b3?','applesaretasty','plum!','plum5','apple','1234','!p1umsareblue'] #list of passwords for testing
#function for checking if password contains special chars
def check_specialchar(pwd):
spec_char_lst=['$','#','#','.','!','?','<','>']
result=any(elem in spec_char_lst for elem in pwd)
if result is True:
print("Has special charactrs")
else:
print("No special characters")
return pwd
for password in passwords_lst: #testing with actual list
print(check_specialchar(password))
#function for checking if length password>6
def check_length(pwd):
if len(pwd)>=6:
print("all ok")
else:
print("length is less than 6")
return pwd
for password in passwords_lst: #testing with actual list
print(check_length(password))
#function for checking if password has at least one digit
def checkif_digit(pwd):
digit_count=0
for char in pwd:
if char.isdigit():
digit_count=digit_count+1 #print("Has digits")
print(digit_count)
#else:
#print("No special characters")
if digit_count>0:
print("Has at least one digit")
return pwd
for password in passwords_lst: #testing with actual list
print(checkif_digit(password))
#function for calling all three tests/functions created above and checking if passwords meet all three conditions
def check_pwd(pwd):
for element in pwd:
return element
print(check_pwd(passwords_lst))
Given the code you already have
I added a print statement to each function to indicate which test is running
Returns True if test passed
I mostly left the existing functions as you wrote them.
Call the other 3 functions from check_pwd
Pass the list to the function and iterate through the values to check them.
#function for checking if password contains special chars
def check_specialchar(pwd):
spec_char_lst=['$','#','#','.','!','?','<','>']
result=any(elem in spec_char_lst for elem in pwd)
print('Special Characters Check:')
if result:
print("Has special charactrs")
return True
else:
print("No special characters")
#function for checking if length password>6
def check_length(pwd):
print('Length Check:')
if len(pwd)>=6:
print("all ok")
return True
else:
print("length is less than 6")
#function for checking if password has at least one digit
def checkif_digit(pwd):
print('Digit Check:')
digit_count=0
for char in pwd:
if char.isdigit():
digit_count=digit_count+1
if digit_count>0:
print(f"Digit count: {digit_count}")
return True
else:
print("No digits")
def check_pwd(pwd_list):
for pwd in pwd_list:
lines = '-'*30
print(f'{lines}\nTesting: {pwd}')
s = check_specialchar(pwd)
l = check_length(pwd)
d = checkif_digit(pwd)
print(f'Passed all checks: {all([s, l, d])}')
passwords_lst = ['ilikeplums!','plum2020','a2b3?','applesaretasty','plum!','plum5','apple','1234','!p1umsareblue', '!thistesttopassall3'] #list of passwords for testing
check_pwd(passwords_lst)
Output of running the function
------------------------------
Testing: ilikeplums!
Special Characters Check:
Has special charactrs
Length Check:
all ok
Digit Check:
No digits
Passed all checks: False
------------------------------
Testing: plum2020
Special Characters Check:
No special characters
Length Check:
all ok
Digit Check:
Digit count: 4
Passed all checks: False
------------------------------
Testing: a2b3?
Special Characters Check:
Has special charactrs
Length Check:
length is less than 6
Digit Check:
Digit count: 2
Passed all checks: False
------------------------------
Testing: applesaretasty
Special Characters Check:
No special characters
Length Check:
all ok
Digit Check:
No digits
Passed all checks: False
------------------------------
Testing: plum!
Special Characters Check:
Has special charactrs
Length Check:
length is less than 6
Digit Check:
No digits
Passed all checks: False
------------------------------
Testing: plum5
Special Characters Check:
No special characters
Length Check:
length is less than 6
Digit Check:
Digit count: 1
Passed all checks: False
------------------------------
Testing: apple
Special Characters Check:
No special characters
Length Check:
length is less than 6
Digit Check:
No digits
Passed all checks: False
------------------------------
Testing: 1234
Special Characters Check:
No special characters
Length Check:
length is less than 6
Digit Check:
Digit count: 4
Passed all checks: False
------------------------------
Testing: !p1umsareblue
Special Characters Check:
Has special charactrs
Length Check:
all ok
Digit Check:
Digit count: 1
Passed all checks: True
------------------------------
Testing: !thistesttopassall3
Special Characters Check:
Has special charactrs
Length Check:
all ok
Digit Check:
Digit count: 1
Passed all checks: True
Using your script as a starting point, I've modified functions to return either True or False depending on whether or not certain conditions are met.
def check_specialchar(pwd):
'''return True if contains special chars, else False'''
spec_char_lst = ["$", "#", "#", ".", "!", "?", "<", ">"]
return any(elem in spec_char_lst for elem in pwd)
def check_length(pwd):
'''return True if len >= 6, else False'''
return len(pwd) >= 6
def checkif_digit(pwd):
'''return True if 1 digit or more, else False'''
return any(char.isdigit() for char in pwd)
def check_pwd(pwds):
"""
return a list containing only valid passwords
"""
res = []
for pwd in pwds:
if check_length(pwd) and check_length(pwd) and checkif_digit(pwd):
res.append(pwd)
return res
Here is an example input and output using passwords_lst.
>>> check_pwd(passwords_lst)
['plum2020', '!p1umsareblue']
You can make each function return a boolean, then use the all() method to see if each function returned True for the password:
def check_specialchar(pwd):
if any(c in '$##.!?<>' for c in pwd):
print("Has special charactrs")
return True
else:
print("No special characters")
def checkif_digit(pwd):
if any(c in "1234567890" for c in pwd):
print('Has at least one digit')
return True
else:
print('Doesn\'t have digits')
def check_length(pwd):
if len(pwd) > 5:
print("length is okay")
return True
else:
print("length is less than 6")
def check_pwd(pwd):
if all([check_specialchar(pwd),checkif_digit(pwd),check_length(pwd)]):
print("Good Password")
else:
print("Bad Password")
Test runs:
Input:
check_pwd("dh756dsdf")
print()
check_pwd("sdfg45?")
Output:
No special characters
Has at least one digit
length is okay
Bad Password
Has special charactrs
Has at least one digit
length is okay
Good Password

How to make Python differentiate between upper and lower characters.

Hello guys I hope you will help me with a small problem that I did not figured out yet.
Here is the description of the homework to have an idea first about what I am working on.
" In this part of the homework, you will write a program that inputs two different
characters in the form of "c1-c2", where c1
is the first character and c2
is the second
character. You need to check the validity of this input. That is, the input should
start with a letter, followed by a dash (-), and it should end with another letter case
insensitively (it means that "a" and "A" are the same characters). Please note that
the characters to be obtained from the user must be different from each other. In
case that the user enters an invalid input, your program should continuously
prompt for the required value until (s)he enters a valid one."
Here is some sample runs:
Please enter two different characters in the form c1-c2: a-A
Invalid input!
Please enter two different characters in the form c1-c2: a-B
(The program should stop if it is correct.)
Here is what I tried so far:
ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def process(Z):
if Z[0] in ascii_letters:
return True
if Z[1] == '-':
return True
if Z[2] in ascii_letters:
return True
if Z[0] != Z[2]:
return True
if Z[0] != Z[2].upper():
return True
if Z[0] != Z[2].lower():
return True
X = False
while X == False:
ask = input("Please enter two different characters in the form c1-c2: ")
if process(ask) == False :
print("Invalid input!")
else:
break
Here your process almost always terminate at the first check:
def process(Z):
if Z[0] in ascii_letters:
return True
You need to nest your condition, and 'return' only when all the conditions are filled, a fast example:
def process(Z):
if Z[0] in ascii_letters:
if Z[1] == '-':
if Z[2] in ascii_letters:
return True
return False
Note you will want to check for that Z is the right size before accessing Z[2]. And you need as well to add the check about same-letter. So a solution for your problem would be:
def process(Z):
if len(Z) == 3
and Z[0] in ascii_letters
and Z[1] == '-'
and Z[2] in ascii_letters
and Z[0].upper() != Z[2].upper():
return True
return False
Strings have methods you can use to validate the input. Use them! You can split on '-' and verify you have 2 characters of length 1, check whether they are alphabetic and compare the upper case version of each.
def process(Z):
parts = Z.split("-")
return (len(parts)==2 and len(parts[0])==1 and len(parts[1])==1
and parts[0].isalpha()
and parts[0].upper() == parts[1].upper())
isalpha works for all unicode characters so you don't have to worry whether the user entered text in some strange language.
The inbuilt function -isalpha() will be helpful for your homework.
while True:
ask=input('Please enter two different characters in the form c1-c2: ')
if len(ask)!=3:
continue
if ask[1] == '-' and ask[0].isalpha() and ask[2].isalpha() and ask[0]!=ask[2]:
break
The isalpha() function returns True if the given string has all alphabets.
The correct way to handle this is with regular expressions. Their is a regex library as part of the standard python library.
import re
u_input = 'your string'
def validate(input):
# chars must be different
if input[0] == input[-1:]:
return False
# begin and end with upper or lower a-z with dash in middle
pattern = '[a-zA-Z]{1}-[a-zA-Z]{1}'
result = re.match(pattern, input)
# re.match returns None if no match
if not result:
return False:
else:
return True
I tried to make it as similar to your code as possible and it's quite simple to understand. I think I considered all required conditions. If not, tell me.
from string import ascii_letters
def validity_check(input_chars):
try:
# if cant be splitted raises Exception which results in restart
char_1, char_2 = input_chars.split("-")
# if characters not in alphabet restarts
chars_in_alphabet = char_1 in ascii_letters and char_2 in ascii_letters
if not chars_in_alphabet:
return False
# if characters are the same letter restarts
same_latter = char_1.lower() == char_2.lower()
if same_latter:
return False
# I'm not sure if you want to check if the first letter
# is small and the second one is capital
# if so add this block
# chars_letter_size = char_1 in ascii_letters.lower() and char_2 in ascii_letters.upper()
# if not chars_letter_size:
# return False
return True
except:
return False
while True:
ask = input("Please enter two different characters in the form c1-c2: ")
if validity_check(ask):
break

Why does islower always return true even when there are digits?

This piece of code uses isdigit() and islower() which both check if a string includes only numbers (isdigit) or only lowercase letters (islower).
If the string given through password contains only numbers or lowercase letters the value should return true and print only numbers if the string only contains numbers or only letters if the string contains only letters, which it does.
However if the password contains numbers and letters for example "12345qwerty" it should return the value false, and go onto the elif statement to check if it has a number or letter included to say add 5 points, and if it still doesn't then it will say try again but it doesn't. It still returns the value as True and print the if statements argument which doesn't make sense, since the password "12345qwerty" contain both letters and numbers and should be returned as false.
import re
password = input("")
if password.isdigit():
print("only numbers ")
elif re.search("[1-9]", password):
print("thats 5 points")
else:
print("try again")
if password.islower():
print("only letters ")
elif re.search("[a-z]", password):
print("thats 5 points")
else:
print("try again")
str.islower() returns true when there are no uppercase letters in the string and there is at least one lowercase letter. That's not the same thing as all characters being letters.
A string with a mix of letters and numbers produces True as well, provided all letters are lowercase:
>>> 'a42b'.islower()
True
>>> 'a42B'.islower()
False
This is clearly documented:
Return true if all cased characters [4] in the string are lowercase and there is at least one cased character, false otherwise.
[4] Cased characters are those with general category property being one of “Lu” (Letter, uppercase), “Ll” (Letter, lowercase), or “Lt” (Letter, titlecase).
If you wanted to test if there were only letters, use str.isalpha():
>>> 'a42B'.isalpha()
False
>>> 'aB'.isalpha()
True
You can combine that with str.islower() to test if there are only lowercase letters:
if password.isalpha() and password.islower():
# only lowercase letters, nothing else.
You can use any to determine if the string has booth numbers and letters and build your cases around that function:
s = "12345qwerty"
def get_val(s):
return not (any(i.isdigit() for i in s) and any(i.islower() for i in s))
print(get_val(s))

Checking a password

I think I have the right idea of solving this function, but I'm not sure why
I don't get the desired results shown in the docstring. Can anyone please help me fix this?
def check_password(s):
'''(str, bool)
>>> check_password('TopSecret')
False
>>> check_password('TopSecret15')
True
'''
for char in s:
if char.isdigit():
if char.islower():
if char.isupper():
return True
else:
return False
Your logic is flawed it should look like this:
def check_password(s):
has_digit = False
has_lower = False
has_upper = False
for char in s:
if char.isdigit():
has_digit = True
if char.islower():
has_lower = True
if char.isupper():
has_upper = True
# if all three are true return true
if has_digit and has_upper and has_lower:
return True
else:
return False
Now, let's talk about what's wrong with your code.
def check_password(s):
for char in s:
if char.isdigit():
if char.islower(): # we only get to this check if char was a digit
if char.isupper(): # we only get here if char was a digit and lower
# it is not possible to get here
# char would have to be a digit, lower, and upper
return True
else:
return False
As an example let's look at TopSecret15, we start with T
isdigit = False so we immediately return false for 'T'
We will continue to immediately return false until we get to '1'
Let's say we were on 1, isdigit would be true, but islower would be false so again it returns false
Do you see how it is impossible for all three of these to be true for the same char?
Your code is equivalent to:
if char.isdigit and char.islower and char.isupper:
# this will never happen
The reason this doesn't work is that for any given character, it first checks if it's a digit, then if it's lower, then if it's upper. Obviously, one character cannot be all three of these at once. You instead want to check each character to see if it's a digit, lowercase, or uppercase, and then flip a boolean value like has_upper. Then, after the for loop, you'll check to see if all of the boolean values are true.
See this answer:
https://stackoverflow.com/a/2990682/7579116
the best way to check if a password match all the requirements is by using a regex.
I've gone way overboard here (because I'm bored I guess) and whipped up an extensible password-checking system. Perhaps it will help clarify why your version doesn't do what you want (or maybe it won't).
The essential problem with your code is that it checks for a single characteristic instead each of the required characteristics.
def check_password(password):
# These are the characteristics we want a password to have:
characteristics = [
length(8), # At least 8 characters
lower_case(1), # At least 1 lower case letter
upper_case(1), # At least 1 upper case letter
number(1), # At least 1 number
]
# Check to see if the supplied password has *all* of the desired
# characteristics:
return all(
characteristic(password)
for characteristic in characteristics
)
def length(n=10):
# Ensure password has at least N characters
def check(password):
return len(password) >= n
return check
def lower_case(n=1):
# Ensure password has at least N lower case characters
def check(password):
count = 0
for char in password:
if char.islower():
count += 1
if count == n:
return True
return False
return check
def upper_case(n=1):
# Ensure password has at least N upper case characters
def check(password):
count = 0
for char in password:
if char.isupper():
count += 1
if count == n:
return True
return False
return check
def number(n=1):
# Ensure password has at least N numbers
def check(password):
count = 0
for char in password:
if char.isdigit():
count += 1
if count == n:
return True
return False
return check
# Doesn't have any numbers:
>>> print(check_password('TopSecret'))
False
# Acceptable:
>>> print(check_password('TopSecret15'))
True
# Has lower case, upper case, and number, but it's not long enough:
>>> print(check_password('Ab1'))
False
Notes:
Some parts of this are simplified in order to make it more clear what's going on (all of the check functions could be one-liners).
In a production system, password requirements will almost certainly change over time and you want to make sure that implementing additional requirements is easy.
A regular expression might not be as easy to understand or extend (although it might be a little faster, but that probably doesn't matter at all).
The approach above is somewhat similar to Django's password validation system.

Categories

Resources