The problem is trying to use strings to prove whether a word or phrase is a palindrome.
def is_palindrome(input_string):
left = 0
right = len(input_string) - 1
while left < right:
if input_string[left] != input_string[right]:
return False
left += 1
right -= 1
return True
This what I attempted to do but when typing in
my_palindrome("race car") it was proven false when it is supposed to be proven true. Need help on finding code to add to this to make punctuation and capitalization negligible.
For characters that aren't letters, there is a string function called .isalpha() that returns True if the string contains only alphabetic characters, False otherwise. You'll need to iterate over each character of the string, retaining only the characters that pass this check.
To make your function case-insensitive, you can use .upper() or .lower(), which returns the string with all the letters upper/lowercased, respectively.
Note that this answer is deliberately incomplete, (i.e. no code), per the recommendations here. If, after several days from the posting of this answer, you're still stuck, post a comment and I can advise further.
Related
The CS50 Problen Set 2 - Plates assignment is to write a program that will validate vanity plate input. The requirements are:
“All vanity plates must start with at least two letters.”
“… vanity plates may contain a maximum of 6 characters (letters or numbers) and a minimum of 2 characters.”
“Numbers cannot be used in the middle of a plate; they must come at the end. For example, AAA222 would be an acceptable … vanity plate; AAA22A would not be acceptable. The first number used cannot be a ‘0’.”
“No periods, spaces, or punctuation marks are allowed.”
My code works, except for the third requirement: "Numbers cannot be used in the middle of a plate..."
My code:
def main():
plate = input("Plate: ")
if is_valid(plate):
print("Valid")
else:
print("Invalid")
def is_valid(plate):
# Check that there is no punctuation
if not plate.isalnum():
return False
# Check that the length is from 2 to 6 characters
if len(plate) < 2 or len(plate) > 6:
return False
# Check to see if the first two letters are alphanumeric
if not plate[0:2].isalpha():
return False
# Check to see that numbers do not start with "0"
for i in range(len(plate)):
# If the current character is a number and the previous character is a letter,
# check if the number is "0".
if plate[i].isnumeric() and plate[i-1].isalpha() and plate[i] == "0":
return False
# Check to see that numbers are not in the middle - this is where the problem lies !
plate = plate[::-1]
for i in range(len(plate)):
if plate[i].isnumeric() and plate[i-1].isalpha():
return False
# If all checks pass, return True
return True
main()
The last section in the is_valid function is supposed to check that a number is never followed by a letter. It does return those inputs as invalid, but also rejects inputs such as "CS50" which should be valid.
In the version above, I have reversed the order of the variable (plate) in an attempt to see if a number follows a digit (which is not allowed in reverse order). I have tried all (I think) combinations of plate[i] and plate [i-1] etc. I have tried substituting isdigit() for isnumeric(), without success.
I know there must be other ways of solving the problem, but I would really like to understand why this code is not working when the code immediately above it does.
When running the code in pythontutor.com, the test seems to fail at the end of the range, where there are two letters, which makes no sense to me.
You have an error with your index.
if plate[i].isnumeric() and plate[i-1].isalpha():
Because it is python, at the start of the loop, the i-1 wraps around to the end of the string. Using i+1 and i raise the same problem the other way around.
You need to change your range() to start and end so that warping does not occur.
The same problem is also present in your previous check. You did not notice because there is an additional condition and the edge cases are filtered by the third check.
how can i remove a single character from a string ?
Basically i have a string like :
abccbaa
I wish to remove the first and last letter. With the string.rstrip or string.lstrip methods all of the occurrences are removed and i get a string bccb. the same goes to replace.
is there a way of doing so ? i cannot import anything , i cant use slicing (except accessing single letter ) . Also I cannot use any kind of loops as well .
To get the whole picture , i need to write a recursive palindrome algorithm. My current code is:
def is_palindrome(s):
if s == '':
return True
if s[0] != s[-1]:
return False
else:
s = s.replace(s[0], '')
s = s.replace(s[-1], '')
return is_palindrome(s)
print is_palindrome("abccbaa")
as you can see it will work unless provides with a string like the one in the print line , since more than "edge" letters are stripped .
Slicing/replacing the string isn't needed and is costly because it creates strings over and over. In languages where strings are much less convenient to handle (like C), you wouldn't even have imagined to do like that.
Of course you need some kind of looping, but recursion takes care of that.
You could do it "the old way" just pass the start & end indices recursively, with a nested function to hide the start condition to the caller:
def is_palindrome(s):
def internal_method(s,start,end):
if start>=end:
return True
if s[start] != s[end]:
return False
else:
return internal_method(s,start+1,end-1)
return internal_method(s,0,len(s)-1)
recursion stops if start meets end or if checked letters don't match (with a different outcome of course)
testing a little bit seems to work :)
>>> is_palindrome("")
True
>>> is_palindrome("a")
True
>>> is_palindrome("ab")
False
>>> is_palindrome("aba")
True
>>> is_palindrome("abba")
True
>>> is_palindrome("abbc")
False
I'm taking a guess at what you are looking for here since your question wasn't all that clear but this works for taking off the first and last character of the word you provided?
Python 2.7.14 (default, Nov 12 2018, 12:56:03)
>>> string = "abccbaa"
>>> print(string[1:-1])
bccba
Testing if a string is a palindrome or not and should be O(n) runtime. We cannot use any import statements or any other helper methods can be used.
So basically my program is to receive an input which is a string that can contain anything. If something in that string is not part of the alphabet it is to ignore it, such as spaces or commas. My program currently works but seems like there should be ways that I could make my program better, by either reducing code or something that I am just unaware of.
An example would be with the string ' E.U.V, vV V,U,E' so the first thing mine does is it goes to string[0] which is just a space and shorts to recalling itself with isPalindrome(string[1]:len(string)-1) so isPalindrome('E.U.V, vV V,U,E').
def isPalindrome (string):
if len(string) <=1: # Basecase to check if the string has less than or equal to 1 element remaining in the string so that the recursion may end
return True
if string.isalpha(): # Checks if the string is all letters of the alphabet and proceeds if true
if (string[0].lower() == string[len(string)-1].lower()): # Compares the lowercase form of the first element and the last element and if they are equal the program will proceed
return isPalindrome(string[1:len(string)-1]) # Function is calling itself with the next elements in the string
else:
return False
else:
if string[0].isalpha(): # Checks if the first element in the string is part of the alphabet and proceeds if true
if string[len(string)-1].isalpha(): # Checks if the last element of the string is part of the element and proceeds if true
if (string[0].lower()== string[len(string)-1].lower()): # Both the first and last element have been confirmed as being part of the alphabet and will not be compared to each other, program proceeds if true
return isPalindrome(string[1:len(string)-1]) # Function is calling itself with the next elements in the string
else:
return False # Program return false when some elements do not equal each other
else:
return isPalindrome(string[0:len(string)-1]) # Function is calling itself with the next elements in the string
else:
return isPalindrome(string[1:len(string)]) # Function is calling itself with the next elements in the string
Well, that is a lot of code for palindrome checking.
Essentially, a palindrome is a string that equals itself if read from the end. You can check that with the slice notation on strings. Now to clean your string from everything that is not a letter, a small list comprehension will do.
def isPalindrome(text):
text = "".join([x for x in text if x.isalpha()])
return text==text[::-1]
I am new to Python (or programming rather) and am trying to learn recursion.
I have written a recursive python function to check if a sentence (not a word) is a palindrome or not.
def checkPalindrome(sentence):
sentence = re.sub('[^\w]', '', sentence.lower())
if len(sentence) == 1:
return True
elif len(sentence) == 2:
return sentence[0] == sentence[1]
else:
return checkPalindrome(sentence[1:-1])
This function works and provides the correct result. Example:
checkPalindrome('Go hang a salami; I’m a lasagna hog')
True
However, since I am removing spaces, punctuations and changing the case of the sentence at the beginning of the function, this step would be computed at every recursive call.
Is there a better way to re-write the function to avoid this?
I think you just answered your own issue: write one function to reduce the input to lower-case letters and call the second one. This second function does the palindrome check and recursion.
However, note that your function doesn't work: the only time it checks the end characters against each other is in the base case of len(sentence) == 2. You need to check just before your recursive call, too:
else:
return sentence[0] == sentence[-1] and
checkPalindrome(sentence[1:-1])
Given this, you could also combine your two base cases:
if len(sentence) <= 1:
return True
Edited per #Joran's suggestion. I've recently been living with too many compiler optimizations; my original is not guaranteed by the Python language definition; this update will work better in the general case.
Pardon the incredibly trivial/noob question, at least it should be easy to answer. I've been working through the coderbyte problems and solving the easy ones in python, but have come across a wall. the problem is to return True if a string (e.g. d+==f+d++) has all alpha characters surrounded by plus signs (+) and if not return false. I'm blanking on the concept that would help navigate around these strings, I tried doing with a loop and if statement, but it failed to loop through the text entirely, and always returned false (from the first problem):
def SimpleSymbols(str):
split = list(str)
rawletters = "abcdefghijklmnopqrstuvwxyz"
letters = list(rawletters)
for i in split:
if i in letters and (((split.index(i)) - 1) == '+') and (((split.index(i)) + 1) == '+'):
return True
else:
return False
print SimpleSymbols(raw_input())
Also editing to add the problem statement: "Using the Python language, have the function SimpleSymbols(str) take the str parameter being passed and determine if it is an acceptable sequence by either returning the string true or false. The str parameter will be composed of + and = symbols with several letters between them (ie. ++d+===+c++==a) and for the string to be true each letter must be surrounded by a + symbol. So the string to the left would be false. The string will not be empty and will have at least one letter."
Any assistance would be greatly appreciated. Thank you!
Here's how I would do the first part (if I weren't using regex):
import string
LOWERCASE = set(string.ascii_lowercase)
def plus_surrounds(s):
"""Return True if `+` surrounds a single ascii lowercase letter."""
# initialize to 0 -- The first time through the loop is guaranteed not
# to find anything, but it will initialize `idx1` and `idx2` for us.
# We could actually make this more efficient by factoring out
# the first 2 `find` operations (left as an exercise).
idx2 = idx1 = 0
# if the indices are negative, we hit the end of the string.
while idx2 >= 0 and idx1 >= 0:
# if they're 2 spaces apart, check the character between them
# otherwise, keep going.
if (idx2 - idx1 == 2) and (s[idx1+1] in LOWERCASE):
return True
idx1 = s.find('+', idx2)
idx2 = s.find('+', max(idx1+1, 0))
return False
assert plus_surrounds('s+s+s')
assert plus_surrounds('+s+')
assert not plus_surrounds('+aa+')
I think that if you study this code and understand it, you should be able to get the second part without too much trouble.
More of a note than an answer, but I wanted to mention regular expressions as a solution not because it's the right one for your scenario (this looks distinctly homework-ish so I understand you're almost certainly not allowed to use regex) but just to ingrain upon you early that in Python, almost EVERYTHING is solved by import foo.
import re
def SimpleSymbols(target):
return not (re.search(r"[^a-zA-Z+=]",target) and re.search(r"(?<!\+)\w|\w(?!\+)",target))