How can I resolve maximum recursion depth error - python

I'm generating a random password with a desired length. I want it to have at least 2 uppercase letters, 2 lowercase letters, 2 digits and 2 special characters. I've tried multiple things, but every time I get this recursion depth error.
Can anybody tell me what I've done wrong?
list_lower =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
list_upper = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N', 'O','P','Q','R','S','T','U','V','W','X','Y','Z']
list_digit = [1,2,3,4,5,6,7,8,9,0]
def generatePassword(desiredLength: int) -> str:
x = 0
password = ""
for x in range (desiredLength):
password = password + chr(random.randint(33,126))
list(password)
list_password = list(password)
times_lower = 0
times_upper = 0
times_digit = 0
times_special = 0
for character in list_password:
if character in list_lower:
times_lower += 1
elif character in list_upper:
times_upper += 1
elif character in list_digit:
times_digit += 1
else:
times_special +=1
if times_lower >= 2 and times_upper >= 2 and times_digit >= 2 and times_special >= 2:
return password
else:
return generatePassword(desiredLength)
generatePassword(7)
I get the error in line 30 which makes the function recursive.

Calling generatePassword(7) will never generate a password with 2 of each of 4 distinct categories.
You don't need recursion at all.
def generatePassword(desiredLength: int) -> str:
while True:
password = ""
for x in range (desiredLength):
password = password + chr(random.randint(33,126))
times_lower = 0
times_upper = 0
times_digit = 0
times_special = 0
for character in password:
if character in list_lower:
times_lower += 1
elif character in list_upper:
times_upper += 1
elif character in list_digit:
times_digit += 1
else:
times_special +=1
if times_lower >= 2 and times_upper >= 2 and times_digit >= 2 and times_special >= 2:
return password
else
print ("Rejecting ", password)
That will loop forever if asked to generate a password of length 7 or less. We can improve that by checking the desired length first
if desiredLength < 8:
raise ArgumentError("Cannot generate passwords shorter than 8 characters")

times_digit will never be >= 2 because it tests stings (e.g. "2" against the integers in your list, (e.g. 2) change your list_digit to
list_digit = ["1","2","3","4","5","6","7","8","9","0"]
and try again.
By the way this could be done much simpler and doensn't need a recursive function.

If you are generating passwords, it's important that you generate ones that actually have enough randomness to not be predictable.
Random string generation with upper case letters and digits in Python
Has a great breakdown of how to generate a password that's truly random:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
(adding "special characters" and "lowercase characters" omitted to preserve the existing code)
I know that this is a somewhat oblique answer (i.e. it does not answer the question directly), so here's a potential solution if you still need the "it must contain these types of characters" (even though that would actually reduce security):
import random
import string
from collections import Counter
def gen(N):
return ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(N))
while True:
pw = gen(8)
counts = Counter(pw)
upper = lower = digit = special = 0
for (letter, count) in counts.items():
if (letter in string.ascii_lowercase):
lower += 1
elif (letter in string.ascii_uppercase):
upper += 1
elif (letter in string.digits):
digit += 1
else:
special += 1
pass
if (lower > 1 and upper > 1 and digit > 1 and special > 1):
print("password is {}".format(pw))
break
print("failed password: {}".format(pw))

Related

How do I count the number of capital letters using a while loop

s = input()
i = 0
while i < len(s) and (s[i]) < "A" or "Z" < s([i]):
print(i)
I keep getting this wrong and I'm not sure what to do. I Do not want to use a for loop just a while loop. Thank you
You can do it by many ways.
If I were you I will do it using isupper() and sum() generator,
s = input("Type something...")
print(sum(1 for c in s if c.isupper()))
Using while as you asked,
s = input("Type something...")
i = 0
capital = 0
while i < len(s):
if s[i].isupper():
capital+=1
i = i + 1
print(capital)
Your while loop is currently written such that it will terminate at the first lowercase letter. You need the loop to go over the entire string, but keep count of uppercase letters as it goes.
s = input()
i = 0
c = 0
while i < len(s):
if "A" <= s[i] <= "Z":
c = c + 1 # c only goes up on capital letters
i = i + 1 # i goes up on every letter
print(i, c)
print(f"Capital letters: {c}")
An easier method is to use the sum function along with isupper:
s = input()
print(f"Capital letters: {sum(c.isupper() for c in s)}")
You are using the while for both the limit and the counting which won't work.
You have to use the while for the limit and an if for the counting:
s = input()
i = 0
count = 0
while i < len(s):
print(i)
if "A" <= s[i] <= "Z":
count += 1
i = i + 1
print(f'Capitals in "{s}" = {count}')
However, this code is very complicated and better is the answer from #AlwaysSunny or the comment from #Samwise
def Capital(In):
return sum([l.isupper() for l in In])
print(Capital(input()))
Try use this:
text = input()
count=0
for letter in text:
if letter == letter.upper():
count+=1
print(letter, end=" ")
print(count-1)
I hope I have explained clearly)

how do i run length encode a pattern, rather than a character?

heres my current RLE code
import re
def decode(string):
if string == '':
return ''
multiplier = 1
count = 0
rle_decoding = []
rle_encoding = []
rle_encoding = re.findall(r'[A-Za-z]|-?\d+\.\d+|\d+|[\w\s]', string)
for item in rle_encoding:
if item.isdigit():
multiplier = int(item)
elif item.isalpha() or item.isspace():
while count < multiplier:
rle_decoding.append('{0}'.format(item))
count += 1
multiplier = 1
count = 0
return(''.join(rle_decoding))
def encode(string):
if string == '':
return ''
i = 0
count = 0
letter = string[i]
rle = []
while i <= len(string) - 1:
while string[i] == letter:
i+= 1
count +=1
#catch the loop on last character so it doesn't got to top and access out of bounds
if i > len(string) - 1:
break
if count == 1:
rle.append('{0}'.format(letter))
else:
rle.append('{0}{1}'.format(count, letter))
if i > len(string) - 1: #ugly that I have to do it twice
break
letter = string[i]
count = 0
final = ''.join(rle)
return final
the code might have gotten fucked up when I removed all my comments, but the current code isn't too important. the problem is, I am running RLE on hexadecimal values, that have all been converted to letters so that 0-9 becomes g-p. the problem is that there are a lot of patterns like 'kjkjkjkjkjkjkjkjlmlmlmlmlmlmlm' which doesn't compress at all, because of their not single characters. how would I, if even possible, be able to run my program so that it encodes patterns as well?

String index out of range despite iterating within a range

I am trying to build a strong password checker using Python. The conditions of the password are as follows:
It has at least 6 characters and at most 20 characters.
It must contain at least one lowercase letter, at least one uppercase letter,
and at least one digit.
It must NOT contain three repeating characters in a row ("...aaa..." is weak, but "...aa...a..." is strong, assuming other conditions are met).
Write a function strongPasswordChecker(s), that takes a string s as input, and return the MINIMUM change required to make s a strong password. If s is already strong, return 0.
Insertion, deletion or replace of any one character are all considered as one change.
The following is my attempt:
import re
class Solution:
def strongPasswordChecker(self, s: str) -> int:
# Holds the change
change = 0
# Checks if the password length is less than 6
if len(s) < 6:
change += 6 - len(s)
# Checks if the password length is greater than 20
elif len(s) > 20:
change += len(s) - 20
# Checks if the password has at least one digit
elif re.search(r'\d', s):
change += 1
# Checks if the password has at least one upper case letter
elif re.search(r'[A-Z]', s):
change += 1
# Checks if the password has at least one lower case letter
elif re.search(r'[a-z]', password):
change += 1
# Checks for repeating characters
for i in range(1, len(s)):
if i >= 3 and i < len(s):
if s[i] == s[i + 1] and s[i + 1] == s[i + 2]:
change += 1
return change
Despite checking for the repeating characters with the if statement above, I'm still getting the following error:
IndexError: String Index out of range
The problem is this statement can go out of bounds potentially, for example when i == len(s) - 1 then s[i + 1] and s[i + 2] will both index out of bounds.
for i in range(1, len(s)):
if i >= 3 and i < len(s):
if s[i] == s[i + 1] and s[i + 1] == s[i + 2]:
change += 1
If you want to make sure you don't have groups of 3 or longer, I'd use itertools.groupby
>>> any(len(list(g)) > 2 for k, g in groupby('aabbcc'))
False
>>> any(len(list(g)) > 2 for k, g in groupby('aabbbbbcc'))
True
To replace your for loop in your code, you'd use this like
elif any(len(list(g)) > 2 for k, g in groupby(s)):
change += 1

Python Caesar cipher changes capitalization of the given input strings

In a ceasar cipher I need it to be that my upper characters remain upper and that non letter character remain non letters/the same. I have it that I can work with lower letters.
Upper letters however are converted to lower and a different letter. Non-letter characters are converted to a lower letter as well. Upper letters must shift but remain upper. Non-letter characters must remain as non-letter character.
p = raw_input(("enter a word"))
n = input(("how many must it shift"))
a = 0
b = 0
c = 0
d = 0
for i in p:
if i.isupper():
a += 1
elif i.islower():
b += 1
elif i.isdigit():
c += 1
else:
d += 1
e = ""
for i in p:
if i == "":
e += i
else:
integerValue = ord(i)
integerValue-= 97
integerValue += n
integerValue %= 26
integerValue += 97
e += chr(integerValue)
print e
You can use i.isalpha() to check if the current character is a letter or not and you can use i.isupper() to check if the current letter is uppercase or not. When you convert the letter you will need to make the letter lowercase and then convert it back to upper. On top of those changes you have too many parenthesis for your inputs. I used raw_input since I'm using python 2.7. Your formatting is so off your code that's posted won't run due to indentation errors and your line if i == "" checks for an empty string instead of a space which I am assuming you were going for. All that said here is what I did to your code to try and keep it similar to what you had while cutting out extraneous bits.
p = raw_input("enter a word")
n = int(raw_input("how many must it shift"))
e = ''
for i in p:
if not i.isalpha():
e+=i
else:
integerValue = ord(i.lower())
integerValue-= 97
integerValue += n
integerValue %= 26
integerValue += 97
if i.isupper():
e += chr(integerValue).upper()
else:
e += chr(integerValue)
print e

python password checker: numbers and symbols

I'm new to python and I'm having a problem. I need to check a password on its upper, lower, numbers and symbols. It needs 1 of each class and the whole password needs to be longer then 6 characters. I have upper and lower case so far. raw_input inputs as a string so how can I then check for numbers and symbols in that string?
My code so far:
p = raw_input(("plz enter a password to check it's strength"))
if len (p) <= 6:
if p.isupper() or p.islower() or int(p):
print"This is a weak password "
elif len(p) > 6 and len(p) <26:
if p.isupper() or p.islower() or isdigit():
print "wea2k"
else:
print "good"
So what I need to know is how to check the input for numbers and symbols.
Try taking the requirements one at a time.
has_upper = False
for char in p:
if char.isupper():
has_upper = True
break
Repeat this for lower case and digits.
For special characters, use the same type of loop, but change the if to something like this:
if not (char.isupper() or char.islower() or char.isdigit()):
At the end, if all four flags are true, then you have a strong password; otherwise, it's weak.
Can you finish the coding from there?
Just so you know, there are ways to code this that are far more "Pythonic" -- that use the language's style much better. For instance:
has_upper = reduce(lambda a, b: a or b.isupper(), [_ for _ in p], False)
... replaces the entire 5-line block that I gave you.
Try this:
p = raw_input(("plz enter a password to check it's strength"))
upper_case = 0
lower_case = 0
number = 0
symbol = 0
for i in p:
if i.isupper():
upper_case += 1
elif i.islower():
lower_case += 1
elif i.isdigit():
number += 1
else:
symbol += 1
if len (p) <= 6:
print"This is a weak password "
elif upper_case > 0 and lower_case > 0 and number > 0 and symbol > 0:
print "Good"
else:
print "Too Weak"

Categories