How to identify if a string is a palindrome?

Asked

Viewed 17,879 times

10

A palindrome is a word or phrase that has the property that can be read from right to left and from left to right. For example, the strings "aaaaa", "1221", "bbaabb" are palindromes, however the string "chef" is not a palindrome.

For cases where a sentence is given, spaces and differences between upper and lower case are ignored. For example: the phrase "A base do teto desaba" is considered a palindrome. When reading it from right to left, you will get: "abased otet od esab A". Note that, with the exception of space, the string is the same as the original sentence.

How to write a program that indicates whether a given string is a palindrome or not, using string knowledge?

  • Hello William, what have you tried to do? Where are your difficulties? So it is better for the community to help you.

  • Make a copy of the string and play in a variable, apply a Verse or similar and compare the original with the copy. It is an initial idea.

  • I haven’t tried any code yet. I just think the right way would be to start with raw_input() so that the user provides a read string, and that using str[::-1] I can make a comparison. To circumvent the spaces, I think to remove them from the initial string so that the comparison works. What do you think?

  • 1

    If to check a single word in the string, this routine: if palavra == palavra[::-1]: could work, otherwise you would have to remove the words, more to check the whole sentence I suggest a look at the other questions on the subject.

  • 2

    Thank you! I’ll try.

  • 3

    Ze de Lima, Laura Street thousand and ten.

  • I’ve managed to write a program that serves its purpose. But there is one condition: The first entry must be an integer number, which corresponds to the number of strings that will be tested. If I provide the number 3, I must provide 3 strings and, after writing the last, the program must make the judgment for each string. I will edit the question and show how I have done so far. How to proceed?

  • @Guilhermesantanadesouza If you have already managed to do the palindrome part, your next question is something more general. I think it is better to leave this question as it is, publish your solution as an answer and open another (that does not mention the palindrome, because you do not need)

  • Understood. Thank you!

  • As I recall, I could sort all the characters and play upside down on a vector and then compare. (To separate you have to do the procedure in ASCI)

Show 6 more comments

9 answers

8


I was able to solve it this way:

string = raw_input()
stringSemEspacos = string.replace(' ', '')
stringTodaMinuscula = stringSemEspacos.lower()
stringInvertida = stringTodaMinuscula[::-1]
if stringInvertida == stringTodaMinuscula:
    print "SIM"
else:
    print "NAO"

After the string is provided by the user, the spaces are replaced by a nullity using replace() (if the string is a phrase), assigning this new string to another variable stringSemEspacos. If the string has uppercase and lowercase letters, the function lower() converts stringSemEspacos in stringTodaMinuscula, which has only lowercase letters. Later, the string is reversed (stringTodaMinuscula[::-1]), and compared with stringSemEspaços. The comparison tests whether stringSemEspaços and stringInvertida (string with inverted letters) are equal. Being equal, the given initial string gives a palindrome.

  • What was the edition?

  • 1

    He added a title to code, but it would be interesting to explain how you solved and how the code works, so you help other people.

  • Ah yes, thank you.

  • Your code could have been shortened to only 6 lines if you did all the passages at once in the string

  • @Viniciusmesel, you were thinking: a=raw_input().replace(' ', '').lower(); print a==a[::-1] ?(Taste: It looks Perl ☺ )

  • 1

    @Guilhermesantanadesouza exactly how I would do!

Show 1 more comment

4

Complementing the other answers...

Most ended up using the Slice [::-1], which generates another string with the characters in reverse order.

This actually works, but if the idea is just to check if the string is equal to its inverse, maybe you do not need to create another string: just iterate by the characters of the same, checking if the first is equal to the last, then if the second is equal to the penultimate, and so on. The detail is that so we only need to iterate up to half the string (besides not having to create another):

def palindromo(string):
    size = len(string)
    if size == 0:
        # Se a string é vazia, ela é ou não é palíndromo? Estou considerando que não
        return False
    for i in range(0, size // 2):
        if string[i] != string[size - i - 1]: # encontrei diferença, nem precisa continuar
            return False
    return True

I was only in doubt about the case of the string being empty (because you can debate whether or not it is palindrome), but anyway, I’m considering that.

Another way to do the same thing, using all:

def palindromo(string):
    size = len(string)
    if size == 0:
        # Se a string é vazia, ela é ou não é palíndromo? Estou considerando que não
        return False
    return all(string[i] == string[size - i - 1] for i in range(0, size // 2))

For cases where a sentence is given, spaces and differences between upper and lower case are ignored.

In this case, the other answers suggest different methods to remove characters that are not letters (such as spaces, scores, etc), and even the use of unicode normalization to treat accents, etc. I believe that the use of such methods varies depending on the need and the cases you want or do not consider, and on this specific point (remove characters that will not be considered in the check) there is not much more to add.

But there are other points I think are worth some consideration:


Ignore difference between upper and lower case

For comparisons case insensitive, the documentation mentions the use of method casefold, which, according to the description, is "more aggressive" than lower (which was the method used in the other responses): "Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string".

An example quoted is from the German character ß, that when converted to uppercase becomes "SS" (example), and so in a comparison case insensitive would be considered equivalent to "ss".

In this case, the above function would have to use casefold at first:

def palindromo(string):
    string = string.casefold()
    # restante do código igual...

Of course, this way we are generating a new string (since casefold returns another string), but at least one string, as the rest of the algorithm continues to iterate to half of it. Now the string 'ßSS' is considered palindromic (but if we used lower in place of casefold, or if we used the first code above, it would not be palindromic).

That is, it is up to you to decide which method to use, since it depends on the criteria to be considered (and also whether the strings you will test will have characters that show this difference).


Unicode and Grapheme clusters

If you want to know in detail what a Grapheme cluster, read here and here, but basically, there can be groups of code points that together mean only one thing (like the emojis of families, in addition to characters used in other languages).

An example is this string: "नुच्छे". It does not seem, but it has 6 code points (and to know what a code point is, visit the links already indicated in the previous paragraph):

s = "नुच्छे"
print(len(s)) # 6
from unicodedata import name, normalize
for c in normalize('NFC', s):
    print(f'{ord(c):06X}\t', c, name(c, ''))

Exit:

6
000928   न DEVANAGARI LETTER NA
000941   ु DEVANAGARI VOWEL SIGN U
00091A   च DEVANAGARI LETTER CA
00094D   ् DEVANAGARI SIGN VIRAMA
00091B   छ DEVANAGARI LETTER CHA
000947   े DEVANAGARI VOWEL SIGN E

Only that the first and second code points "come together" in one grapheme cluster (become "one thing"), which in this case is the character नु. The same is true of the others: each 2 code points come together to form a single character. And in this case, it is no use to use Unicode normalization (as used in the example above), that they will remain separate.

So if I have a string like "नुच्छेच्नु" (the first and last are the same grapheme cluster, as well as the second and penultimate), the function palindromo does not work anymore, because when accessing the characters of a string, we are actually accessing the code points individually. And in this case also no use [::-1], because then you will be reversing the order of the code points, generating an invalid string (since the order of the code points is important in a grapheme cluster).

The same goes for emojis family, which are actually a joint of several code points. Ex:

s = ''.join(map(chr, [0x1F468, 0x200d, 0x1F469, 0x200d, 0x1F467, 0x200d, 0x1F467]))
print(s)

If your terminal/IDE supports emojis, will be shown something like:

Of course the image varies according to the system (and if not supported, can be shown the man, the woman and the children next to each other, for example).

What matters is that this is a grapheme cluster: a group of several code points that are considered one thing. And none of the methods presented so far consider that this is a palindrome (it would be like a string containing a single "character", since when reversing it, the result should be the same emoji).


Then there’s not much of a choice but to treat grapheme clusters one by one. You can both read the unicode document and implement the rules, or else use something ready.

One example I found is module grapheme. With it we can break the string into grapheme clusters and use the same algorithm above (compare the first with the last, the second with the penultimate, etc):

# Atenção: módulo não-nativo - Instale em https://pypi.org/project/grapheme/
from grapheme import graphemes

def palindromo(string):
    grapheme_clusters = list(graphemes(string.casefold()))
    size = len(grapheme_clusters)
    if size == 0:
        # Se a string é vazia, ela é ou não é palíndromo? Estou considerando que não
        return False
    for i in range(0, size // 2):
        if grapheme_clusters[i] != grapheme_clusters[size - i - 1]: # encontrei diferença, nem precisa continuar
            return False
    return True

s = "नुच्छेच्नु"
print(palindromo(s)) # True

# funciona também para o emoji de família
s = ''.join(map(chr, [0x1F468, 0x200d, 0x1F469, 0x200d, 0x1F467, 0x200d, 0x1F467]))
print(palindromo(s)) # True

# continua funcionando para strings "normais"
for s in ['aba', 'a', '', 'ab', 'aa', 'abc', 'abcdedcba', 'aabbaa', 'ßSS']:
    print(s, palindromo(s))

Or, using all:

def palindromo(string):
    grapheme_clusters = list(graphemes(string.casefold()))
    size = len(grapheme_clusters)
    if size == 0:
        # Se a string é vazia, ela é ou não é palíndromo? Estou considerando que não
        return False
    return all(grapheme_clusters[i] == grapheme_clusters[size - i - 1] for i in range(0, size // 2))

Of course it was lacking to apply the removal of unwanted characters (spaces, punctuation, etc), but as already said, just see the other answers and choose the one that best meets your need (since the removal is orthogonal to the treatment of grapheme clusters).

2

Here’s a simplified way I found to resolve the issue.

Here comes the code..

palavra_1 = str(input('Qual palavra deseja verificar se é um palídromo? '))
palavra_2 = palavra_1.lower().strip().replace(' ', '')
if palavra_2 == palavra_2[::-1]:
    print(palavra_1)
    print('É um palídromo')
else:
   print('Não é um palídromo')

2

To decide a sentence is palindromic or not, ignoring blank spaces, dots and commas.

frase = raw_input('Informe uma frase').split(" ")  # retira espaço em branco
aux = ""

for i in range(0, len(frase)):
    aux += frase[i]

frase = aux.split(".") #retira os pontos
aux = ""

for i in range(0, len(frase)): #retira os pontos
    aux += frase[i]

frase = aux.split(",") #retira as vírgulas
aux = ""

for i in range(0, len(frase)): #retira as vírgulas
    aux += frase[i]

if aux.lower() == aux.lower()[::-1]: #verifica usando minúsculo e invertido
    print 'É palíndromo'
else:
    print 'Não é palíndromo'

I hope it helped...;-)

0

One of the ways to check whether a word is palindromic is:

palavra = input('Digite uma palavra: ').lower().strip().replace(' ', '')
if palavra == palavra[::-1]:
    print('É palíndromo')
else:
    print('Não é palíndromo')

Now if you prefer a function to check if a word is palindromic you can use the following code:

def palindromo(pala):
    if pala == pala[::-1]:
        return True
    return False


palavra = input('Digite uma palavra: ').lower().strip().replace(' ', '')

print(palindromo(palavra))

Also note that the output of this second code is only a statement - True or False .

Note that when we run both the codes we received the following message: Digite uma palavra: . At this point we must type the desired word and press enter. Then the block if of both codes will check whether word is equal to reverse of the word. If yes, the answer will be positive. If no, the answer will be negative.

Observing: The reverse of a word is the writing of the word in opposite direction.

-1

I challenge you to find a palindrome or a palindrome not detectable by this algorithm!

We need to normalize the text before comparing to its inverse, otherwise an accent can generate a false negative. To normalize, we will use the normalize('NFKD', s), which converts to unistr and applies the compatibility decomposition, that is, replace all the compatibility characters with their equivalents (https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize). We convert to 'ASCII', so the accented characters will be exchanged for their accented equivalents and ignoring those that do not have equivalence. We turn the text to Unicode, convert it to minuscules and finally use regex to leave only a-z, A-Z and 0-9 (A palindrome with numbers is possible)

import re
from unicodedata import normalize

def slugfy(s):
    """
    Remove caracteres e acentos ignoráveis
    """
    return re.sub('[^a-zA-Z0-9]+','', normalize('NFKD', s).encode('ASCII','ignore').decode('ASCII')).lower()

def is_palindrome(s):
    """
    Verifica se é igual a ao termo invertido ignorando espaços
    e termos fora do range A-z0-9
    """
    s = re.sub('\s+','',s) # remove whitespaces
    return bool(s and s == s[::-1] or slugfy(s) and slugfy(s) == slugfy(s)[::-1])

text = is_palindrome(
    input('Digite um palindromo: ')
)

if text:
    print('Habemos um palindromo!!!')
else:
    print('Tentei ler de traz pra frente e não deu certo amigão!')

Best known palindromes to test:

palindromos = [
    "Roma me tem amor.",
    "Socorram-me, subi no ônibus em Marrocos!",
    "A mala nada na lama. ",
    "A grama é amarga. ",
    "A Rita, sobre vovô, verbos atira.",
    "Olé! Maracujá, caju, caramelo!",
    "Rir, o breve verbo rir.",
    "Anotaram a data da maratona.",
    "A mãe te ama.",
    "Oto come mocotó.",
    "A torre da derrota.",
    "Ótimo, só eu, que os omito.",
    "O galo ama o lago.",
    "O lobo ama o bolo.",
    "Mega bobagem.",
    "A cara rajada da jararaca.",
    "Amar dá drama.",
    "A sacada da casa.",
    "Após a sopa.",
    "Luz azul.",
    "Ame o poema.",
    "A dama admirou o rim da amada.",
    "A diva em Argel alegra-me a vida.",
    "O caso da droga da gorda do saco.",
    "Zé de Lima, Rua Laura, Mil e Dez",
    "Saíram o tio e oito marias.",
    "Assim a aia ia a missa.",
    "Adias a data da saída.",
    "Acuda cadela da Leda caduca.",
    "Aí, Lima falou: “Olá, família”.",
    "A pateta ama até tapa.",
    "E até o Papa poeta é.",
    "Laço bacana para panaca boçal.",
    "A gorda ama a droga.",
    "Lava esse aval.",
    "Soluço-me sem óculos.",
    "Missa é assim.",
    "Nos ligou o Gilson!",
    "Até time demite, tá?",
    "Irene ri.",
    "Olá, galo!",
    "Ai, Bia! ",
    "Ali, lado da Lila.  ",
    "Amor a Roma.",
    "Até o poeta.",
    "Ladra pardal.",
    "Livre do poder vil. ",
    "O céu sueco.",
    "Ser belo: lebres. ",
    "Lá vou eu em meu eu oval.",
    "Eco: vejo hoje você.",
    "O muro: rever o rumo.",
    "Orava o avaro.",
    "A Daniela ama a lei? Nada!",
    "A droga do dote é todo da gorda.",
    "A lupa pula.",
    "A miss é péssima!",
    "À Rita, sátira!",
    "Acata o danado... e o danado ataca!",
    "Ajudem Edu já!",
    "A base do teto desaba.",
    "Eva, asse essa ave!",
    "Marujos só juram.",
    "O mito é ótimo.",
    "O trote torto.",
    "O treco certo.",
    "O trote torto.",
    "O voo do ovo.",
    "Ódio do doido!",
    "Oh nossas luvas avulsas, sonho... ",
    "Oi, rato otário!",
    "A rua Laura.",
    "Ato idiota.",
    "Arara rara.",
    "O teu dueto.",
    "A babá baba.",
    "Pivete vip!",
    "O Atari piratão.",
    "Roda esse corpo, processe a dor!",
    "Seco de raiva, coloco no colo caviar e doces.",
    "Amo Omã. Se Roma me tem amores, amo Omã!",
    "Me vê se a panela da moça é de aço, Madalena Paes, e vem.",
    "Luza Rocelina, a namorada do Manuel, leu na moda da Romana: anil é cor azul.",
    "O duplo pó do trote torpe de potro meu que morto pede protetor todo polpudo.",
    "O romano acata amores a damas amadas e Roma ataca o namoro.",
]
  • 1

    Good! By the way, welcome to Stack Overflow in Portuguese! But I think it’s worth explaining how the code works. Many people may not understand why you are using the function normalize there. The encode for ASCII is also kind of mysterious. If you want to clarify (what I recommend), it’s just edit the answer. :-)

  • 1

    https://ideone.com/Wu1EH1 <- it’s okay that I "appealed" and used characters outside our alphabet, but anyway, it’s still a word, right? : -) (the word I used is not palyndrome, but the function says it is, since you deleted everything that is not ASCII, so the string I tested turns into an empty string). As a curiosity, I left an answer who deals with such cases :-)

  • Thanks @hkotsubo! I corrected the false positive

-3

To know if the word is palyndrome or not, using function. Explanation of some commands: ". Lower()" -> Returns the whole word in lower case letters. " [::-1]" -> returns the word backwards. " end='' " -> Makes the response stay on the same ad line as if it were just to continue on the same line.

def result(palavra):
    palavra_min = palavra.lower()
    palavra_invertida = palavra_min[::-1]
    if palavra_min == palavra_invertida:
        print("A palavra é palíndroma.")
    else:
        print("A palavra não é palíndroma.")
    print()
    print('Sua palavra: ', end='')
    print(palavra)
    print('Inversão: ', end='')
    print(palavra_invertida)


word=input('Digite uma palavra: ')
print(result(word))

                                                                   #Pedreiro
  • 2

    Don’t get me wrong, but in my view your answer added nothing compared to the previous answers. Same logic, same functions. In fact, if you want to print strings on the same line, you can pass them as a function parameter print (see here), do not need to use the end and call the function again.

  • I appreciate the criticism, but the idea was only to show an alternative to more. I thank you for the tip.

-4

frase = str.upper(input('Digite uma frase: ')).strip()
fraseLimpa = str.replace(frase, ' ','')
print('A frase "{}" eh um polindromo?'.format(frase))
if fraseLimpa == fraseLimpa[::-1]:
    print('Sim')
else:
    print('Nao')

-4

To decide whether the word is or is not palyndrome

f=input('Digite uma frase:  ')
if f==f[::-1]:
    print('A frase é palíndromo --> %s'%(f))
else:
    print('A frase não é palíndromo --> %s'%(f))
  • 4

    Hello colleague. Do not take the comment wrong, but this response does not seem to complement at all the existing answer, which was given in 2016 and has exactly the same solution.

  • 1

    I think he took it from here https://caveiratech.com/forum/programm_development_bankdatas/saber-se-a-palavra-e-palindrome-python/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.