Individually, these statements work (I've made individual helper functions) and I've compiled them onto one function. How am I able to get them to work together? Additionally, how would I make this program run without module 're'? It works but I got it off someone else on this site. These are what I need in this program:
Has to have a number
Characters in the beginning and end of the string have to be letters
Must be between 10 and 20 characters
There can't be 3 characters in a row
Previous password can't be used again
Here is my code:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if 10 <= len(s) <=20:
return True
elif s[0] and s[-1].isalpha():
return True
elif not re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return True
elif any(digit.isdigit() for digit in s):
return True
else:
return False
Your code checks if the input satisfies only one of the conditions.
Note that when you return, the function returns and ignores the rest of the code. Considering this fact, you can use either:
(1) Nested ifs
if 10 <= len(s) <= 20:
if s[0] and s[-1].isalpha():
# the rest of the conditions
return True # all of the conditions were met
return False # one of the conditions wasn’t met
(2) Return false when one the first condition isn't met (which actually uses De Morgan's laws).
if not 10 <= len(s) <= 20:
return False
if not s[0] and s[-1].isalpha():
return False
# the rest of the conditions
Regarding the regex use, in my opinion it's elegant in this case; but you can always switch to a loop that iterates over the input's characters, combined with a counter of repeated characters (which isn't as elegant):
def three_identical_characters(input):
counter = 0
for i in range(1, len(input)):
counter += (1 if (input[i] == input[i-1]) else 0)
if counter == 2:
return True
return False
Store each of the conditions results in a variable, e.g. has_correct_length and has_digit.
Combine them:
has_correct_length = (10 <= len(s) <=20)
has_digit = any(digit.isdigit() for digit in s)
fulfills_restrictions = has_correct_length and has_digit
This way your code is much easier to read and documents itself.
You don't test if the condition is met, you test if the condition is not met:
import re
def password_validator (pw_v, prev_p): #pw_v = string that is to be validated; prev_p = previously used strings in a list
prev_P = [s]
# do I use 'while True' instead of returning True statements every time?
if not 10 <= len(s) <=20:
return False
elif not (s[0] and s[-1].isalpha()):
return False
elif re.search('(.)\\1{2}', s): # How else can I write this without using 're'?
return False
elif not any(digit.isdigit() for digit in s):
return False
else:
return True
Related
I am trying to learn while loops.
To practice, I created a simple while loop with an If statement inside a function to check and see if a word is a palindrome. For some reason, even if the word is not a palindrome, it keeps returning True.
I expected the output of the print function on the last line to be False:
from collections import deque
word = "tacrocat"
def check_palindrome(word):
d = deque(word)
while len(d) > 1:
if d.pop() == d.popleft():
return True
return False
print(check_palindrome(word))
NOTE: When I change the if statement evaluation to "!=", change the return statement inside the if statement to False, and change the return statement in the while loop to True, it seems to accurately detect palindromes - but I have no idea why.
If the program is written like this:
from collections import deque
word = "tacrocat"
def check_palindrome(word):
d = deque(word)
while len(d) > 1:
if d.pop() == d.popleft():
return True
return False
print(check_palindrome(word))
At iteration-1:
Since both the first character('t') and last character('t') in the deque are equal it will enter the if condition and return True. When a return statement is executed in a function, then the control comes out of the function. In other words, as soon as return True statement is executed, the control comes back to print statement without executing remaining iterations of while loop and since we returned True, so True will be printed as output.
Let's analyze second program:
from collections import deque
word = "tacrocat"
def check_palindrome(word):
d = deque(word)
while len(d) > 1:
if d.pop() != d.popleft():
return False
return True
print(check_palindrome(word))
At iteration-1:
Current deque: [t,a,c,r,o,c,a,t]
We are popping both first element and last element and checking whether they are not equal in if condition. Since 't' and 't' are equal, if condition will not execute and while loop will continue.
At iteration-2:
Current deque: [a,c,r,o,c,a]
Since 'a' and 'a' are equal, if condition will not execute and while loop will continue. Both first and last elements are popped (pop and popleft)
At iteration-3:
Current deque: [c,r,o,c]
Since 'c' and 'c' are equal, if condition will not execute and while loop will continue. Both first and last elements are popped (pop and popleft)
At iteration-4:
Current deque: [r,o]
Since 'r' and 'o' are not equal, if condition will execute and return False statement is executed. So, the function check_palindrome will terminate with return value as False and so we get output as False.
The second program is correct because to check if a word is palindrome or not, we need to check all letters whether they are satisfying the condition or not. Just checking only the first and last character of a word and if they are equal, then it doesn't mean the remaining letters are same. We need to check them too.
Once it finds a return True it will come out of the function.
In the first iteration it will compare t with t and exit the function.
In your case it comes out at first letter.
rather you can do as stated by #Goodies in comment
from collections import deque
word = "tacrocat"
def check_palindrome(word):
d = deque(word)
while len(d) > 1:
if d.pop() != d.popleft():
return False
return True
print(check_palindrome(word))
This is happening because it is returning True if any one of the characters on either side of centre are equal. This is probably confusing but basically it checks if any of the letters are mirrored not all of them because the return True exits early.
This means that, actually, your function does not always return True, for example a word like "word" would return false.
To fix this, rather than return True when one match is found and otherwise return False, you could return False if any do not match and else return True like so (see comment above by #Goodies):
from collections import deque
word = "tacrocat"
def check_palindrome(word):
d = deque(word)
while len(d) > 1:
if d.pop() != d.popleft():
return False
return True
print(check_palindrome(word))
which (correctly) outputs:
False
I need to write this iterative function to do the same thing but it must be recursive.
def task1(string: str):
for i in range(len(string)):
if string[i] != string[len(string) - i - 1]:
return False
return True
This is what i tried but it does not work.
def task1_recursion(string: str):
print(string)
if len(string) > 1:
if string[0] == task1_recursion(string[1::1]):
return True
else:
return False
else:
return string
My code seems to one the last recursion return string "" and that makes it to return False.
Just check the tip and the tail, continue with the string without them:
def task1_recursion(string: str):
# recursion base condition (exit condition)
if len(string) <= 1:
return True
# unpack values
first, *_, last = string
# check if they are different
if first != last:
return False
# if not continue checking the remaining string
return task1_recursion(string[1:-1])
If I understand correctly you want to check if a string is symmetric with the code in task1. My solution is below:
def fct(s: str, i: int):
if len(s) <= 1 or i == len(s):
return True
return s[i] == s[len(s) - 1 - i] and fct(s, i + 1)
I tested and fct produces the same result as task1. It needs an additional parameter for the index though. But you can wrap it inside another function if you want the parameter to include only the input string. i is always set to 0 when you call the function, e.g. fct("ABCCBA", 0).
I got stuck on a homework problem where I need to write a function that takes in one parameter and returns True if there are exactly three 7's in a string. If there are less than three or more than three '7's, the function should return False.
def lucky_seven(a_string):
if "7" in a_string:
return True
else:
return False
print(lucky_seven("happy777bday"))
print(lucky_seven("happy77bday"))
print(lucky_seven("h7app7ybd7ay"))
The result should be True, False, True. I got I to work where only one 7 is in a string. Appreciate if anyone can point me into the right direction.
you can use str.count:
str.count(sub[, start[, end]])
Return the number of non-overlapping occurrences of substring sub in
the range [start, end]. Optional arguments start and end are
interpreted as in slice notation.
def lucky_seven(a_string):
if a_string.count("7") == 3:
return True
else:
return False
print(lucky_seven("happy777bday"))
print(lucky_seven("happy77bday"))
print(lucky_seven("h7app7ybd7ay"))
You an do it by using regexp easily:-
import re
def lucky_seven(text):
return len(re.findall("7", text)) is 3
print(lucky_seven("happy777bday"))
print(lucky_seven("happy77bday"))
print(lucky_seven("h7app7ybd7ay"))
"7" in a_string is True iff there are any 7's in a_string; to check for a certain number of 7s, you could compare each character of a_string to 7 and count how many times they match. You could also do this with a regex.
You could just create your own counter like -
def lucky_seven(a_string):
count = 0
for s in a_string:
if s == "7":
count += 1
return True if count == 3 else False
Or you could use python's collections module, which will return a dict of how many times an element has appeared in a list. Since a string is nothing but a list, it will work -
import collections
def lucky_seven(a_string):
return True if collections.Counter("happy777bday")["7"] == 3 else False
Or a string counter-
def lucky_seven(a_string):
return True if str.count(a_string, "7") == 3 else False
Or even a list comprehension solution, though really not needed -
def lucky_seven(a_string):
return True if len([i for i in a_string if i == "7"]) == 3 else False
so I'm new to programming (and python) and I have to make this program that returns True if the string has zero or one dot characters ("." characters) and return False if the string contains two or more dots
here is what I currently have, I cannot get it to work for me, please correct me if I am wrong, thanks!
def check_dots(text):
text = []
for char in text:
if '.' < 2 in text:
return True
else:
return False
Use the builtin Python function list.count()
if text.count('.') < 2:
return True
It can be even shorter if instead of an if-else statement, you do
return text.count('.') < 2
Also, there are some errors in your function. All you need to do is
def check_dots(text):
return text.count('.') < 2
A correct and shorter version would be:
return text.count('.') <= 1
Python has a function called count()
You can do the following.
if text.count('.') < 2: #it checks for the number of '.' occuring in your string
return True
else:
return False
A shortcut would be:
return text.count('.')<2
Let's analyze the above statement.
in this part, text.count('.')<2: It basically says "I will check for periods that occur less than twice in the string and return True or False depending on the number of occurences." So if text.count('.') was 3, then that would be 3<2 which would become False.
another example. Say you want it to return False if a string is longer than 7 characters.
x = input("Enter a string.")
return len(x)>7
The code snippet len(x)>7 means that the program checks for the length of x. Let's pretend the string length is 9. In this case, len(x) would evaluate to 9, then it would evaluate to 9>7, which is True.
I shall now analyze your code.
def check_dots(text):
text = [] ################ Don't do this. This makes it a list,
# and the thing that you are trying to
# do involves strings, not lists. Remove it.
for char in text: #not needed, delete
if '.' < 2 in text: #I see your thinking, but you can use the count()
#to do this. so -> if text.count('.')<2: <- That
# will do the same thing as you attempted.
return True
else:
return False
I'm working my way through the MIT 6.00 class on OpenCourseWare and I'm having a little trouble with the lecture on recursion. I think I understand the basic idea, that you can break some problems down into smaller, repeatable problems. Where I'm having trouble is understanding how this works in the actual code. There is one specific example that I don't quite understand...
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
This code is supposed to check if a string is a palindrome or not. I am a little lost on how isPal(s) works. Here's the steps as I'm reading them...
Check if s is one character or less, if it is return True.
If s has more than one character return a Boolean value (True or False) from the expression comparing the first and last character. So basically check if the first and last letter are the same.
AND return the result of the function run again with the first and last letters stripped from the string.
What is confusing me is the return s[0] == s[-1] and isPal(s[1:-1]) bit. I'm not sure I understand what it means to both return True/False based on the first expression AND return the function. Honestly I'm not even sure what returning the function actually means, I'm guessing it just runs the function again, but doesn't actually return any value. I also don't understand how this can actually tell if a string is a palindrome or not. Wouldn't it just keep hitting the second part of return s[0] == s[-1] and isPal(s[1:-1]) until the string, whether it was a palindrome or not, was reduced to 1 or 0 characters? The only thing I can think of is that returning a false value from return s[0] == s[-1] exits the function with a return of false? But I don't feel like that's actually how Python works, at least in my study so far I haven't run into anything saying that returning a False in a function would prevent the second part of the return statement from executing, which would call the function again regardless of whether the first and last letters where the same.
I'm kind of banging my head against the wall at this point, so any insight would be really appreciated!
Perhaps the best way is to go step by step with the values for that line that is confusing you.
return s[0] == s[-1] and isPal(s[1:-1])
Assuming the String you're testing for is "ABCDBA", here is the sequence of calls
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate to ("A" == "A" and isPal("BCDB")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate ("B" == "B" and isPal("CD")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #returns ("C" == "D")
Note that in the last line we didn't evaluate for isPal because of short-circuiting - we know that False and X where X can be True or False is always False. Read more about that here.
At the last line we're 4 functions deep into isPal. Since the last line doesn't require us evaluate for isPal() again, we start "rising to the surface" back to the original invocation of isPal which was at
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
One clarification which can help you understand what's going on: return ...X and ...Y means: Compute the value of X. If the value is false, return it, otherwise compute the value of Y, and return it.
More info about the short-circuit, lazy behavior (i.e. not evaluating Y if not needed) of the and and or operators in Python: https://docs.python.org/release/2.7/reference/expressions.html#boolean-operations
So that statement doesn't make the function return two values (X and Y), but one value which is the logical AND of X and Y: it's true iff both X and Y are (evaluated to) true.
Also it's worth distinguishing function from function call. There can be many active calls to the same function, with different arguments, local variables etc., so their return values can also be different (as soon as they return). When a function calls itself, that's called recursion. When a function call returns, execution continues in the caller, which can be the same function (but of course a different, upper-level function call) in case of recursion.
If you run the isPal function on "heeeeh" with print statements:
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("heeeeh")
You get:
h h
e e
e e
True
as each char at index s[0] and s[-1] are equal through each recursive call as the string is a palindrome.
Running it on "aeeee":
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("aeeeeh")
You get :
a h
False
As as soon as s[0] and s-[1] are not equal the functions ends and returns False as it cannot be a palindrome if the chars are not equal.
I'll add my explanation, maybe this will help you.
First things first:
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
will simply take some text and turn it all to lower case, character by character.
Next is:
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
To understand this part you ask yourself a question, what is a palindrome and what are ways to know if word or sentence is one.
In this example approach is: palindrome is word or sentence where its characters in same distance from beginning and from the end are the same characters.
So how to check that? Well, first if your word is just one letter or shorter then it's a palindrome.
Then you check if letters at the beginning and the end of your word are the same.
You remember the result as true or false and strip your word from letters you already checked and repeat the process until your word is 1 or less characters long and check if every result of comparison was true.
Example:
Foob->foob
f=b? NO, false
Example 2:
Fbof->fbof
f=f? Yes, true,
bo
b=o? No, false.
true and false = false, so the word is not a palindrome
Example 3:
Fobof->fobof
f=f? Yes, true,
obo,
o=o? Yes, true
b
len(b) = <=1 ? Yes, true,
true and true and true = true, so the word is a palindrome.
Hope it helps, ask if you need more thorough explanation, I'll try to help, no worries, i struggled with recursion at the beginning as well.