Solution Exercise 45

Write a version of a palindrome recognizer that also accepts phrase palindromes such as 
"Go hang a salami I'm a lasagna hog." 
"Was it a rat I saw?" 
"Step on no pets" 
"Sit on a potato pan, Otis" 
"Lisa Bonet ate no basil" 
"Satan, oscillate my metallic sonatas" 
"I roamed under it as a tired nude Maori" 
"Rise to vote sir" 
"Dammit, I'm mad!" 
Note that punctuation, capitalization, and spacing are usually ignored.

import re

#Version using more or less the same solution as in exercise 8
def is_palindrome_v1(text):
    #Set front to index the first character in text
    front = 0
    #Set end to index the last character in text
    end = len(text)-1
    #We need to skip any non alphabetic characters in the front of the string
    while not text[front].isalpha():
        front += 1
    #And the same thing at the end of the string
    while not text[end].isalpha():
        end -= 1

    #Repeat as long as the characters are equal and front is less than end
    while text[front].lower() == text[end].lower() and front < end:
        #Move to the next character
        front += 1
        #Move to the next character
        end -= 1
        #If we at this have a front is greater than end we are done and this is not a palindrome
        if front > end:
            return False
        #Skip all non alphabetic characters
        while not text[front].isalpha():
            front += 1
        while not text[end].isalpha():
            end -= 1
    #If front is less than end this can't be a palindrome
    if front < end:
        return False
    #This must be a palindrome
    return True

#Version using regex
def is_palindrome_v2(text):
    #Create the regex
    regex = re.compile("[^a-zA-Z]")
    #Delete all spaces and all non alphabetic characters
    text = regex.sub("",text).replace(" ","").lower()
    
    #Now we can treat it as we did in exercise 8
    front = 0
    end = len(text) -1
    while text[front] == text[end] and front < end:
        front += 1
        end -= 1
    if front < end:
        return False
    return True    

#Version using regex and join and reversed
def is_palindrome_v3(text):  
    #Create regex
    regex = re.compile("[^a-zA-Z]")
    #Delete all spaces and all non alphabetic characters
    text = regex.sub("",text).replace(" ","").lower()
    #Create a backward copy of the string using reversed
    #We need to use join to transform the result into a string
    backward_text = "".join(reversed(text))
    return text == backward_text

def main():
    palindromes = ["Go hang a salami I'm a lasagna hog.", 
                   "Was it a rat I saw?", 
                   "Step on no pets", 
                   "Sit on a potato pan, Otis", 
                   "Lisa Bonet ate no basil", 
                   "Satan, oscillate my metallic sonatas", 
                   "I roamed under it as a tired nude Maori", 
                   "Rise to vote sir", 
                   "Dammit, I'm mad!",
                   "I'm not a palindrome"] 

    for phrase in palindromes:
        if is_palindrome_v1(phrase):
            print(phrase, "- is a palindrome")
        else:
            print(phrase, "- is not a palindrome")

        if is_palindrome_v2(phrase):
            print(phrase, "- is a palindrome")
        else:
            print(phrase, "- is not a palindrome")

        if is_palindrome_v3(phrase):
            print(phrase, "- is a palindrome")
        else:
            print(phrase, "- is not a palindrome")
       
if __name__ == '__main__':
    main()