So I created this code that takes in a list and returns True or False depending on whether they meet these criterias or not. Here is my 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
else:
return True
return False
Now I want to add a new twist, which is that if any letter, number, character in the list appears 3 times in a row, the result will return False.. here is my attempt at it...
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
for char in password:
if password.count(char) > 3:
return False
return True
return False
However, this clearly doesn't work at all.. what am I doing wrong here?? what should my code be in order for my output to be correct??
CodePudding user response:
Use groupby
from itertools
. With this version, you set the number of characters in a row.
from itertools import groupby
def passwordinarow(password: str, n: int=3):
"""Return True if password contains 'n' characters in a row else False."""
return any([len(list(g)) >= n for c, g in groupby(password)])
Test:
>>> passwordinarow('AAABC123$')
True
>>> passwordinarow('ABC123$')
False
CodePudding user response:
If you want to return false
when a character, number appears 3 times in the string, clearly you should change your if condition like this:
[...]
for char in password:
if password.count(char) == 3:
return False
[...]
If you meant at least 3 times appearance:
[...]
for char in password:
if password.count(char) >= 3:
return False
[...]
However password.count(char)
will loop over the whole password
for each char
, so why don't we loop once, and get the result:
[...]
from collections import defaultdict
defdict = defaultdict(lambda: 0)
for char in password:
defdict[char] = 1
if defdict[char] >= 3:
return false
[...]
Update:
according to your comment:I mean like 3 times in a row btw, like if its AAA, BBB, CCC then it should return false.. if it's ABANA.. then it doesn't matter
Define a function like this:
def has_3consecutive_char(password: str) -> bool:
from collections import defaultdict
defdict = defaultdict(lambda: 0)
prev_char = ""
for char in password:
if prev_char == char:
defdict[char] = 1
if defdict[char] >= 2:
return True
else:
defdict[char] = 0
prev_char = char
return False
Then use it in your passwordOK
function:
def passwordOK(password: str):
if passwordlength(password):
if not (6 < len(password) < 12):
return False
if has_3consecutive_char(password):
return False
return True
return False
CodePudding user response:
There are many different ways to approach this.
Personally I might do something like:
def has_repeated_chars(password: str, n_repetitions: int=3) -> bool:
ngrams = zip(*(password[i] for i in range(n_repetitions)))
return min(len(set(trigram)) for trigram in ngrams) == 1
Generally the logic is to create an iterable of ngrams of length 3, create a set for each ngram and if the set is of length 1 then we know the same character has been repeated 3 times.