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).
Hello William, what have you tried to do? Where are your difficulties? So it is better for the community to help you.
– gato
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.
– rray
Related: Palindromic string inversion, Palindrome in C++ and I need different ways to rearrange characters within a string, how do I do this?
– rray
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?
– Guilherme Santana De Souza
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.– gato
Thank you! I’ll try.
– Guilherme Santana De Souza
Ze de Lima, Laura Street thousand and ten.
– Bacco
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?
– Guilherme Santana De Souza
@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)
– Pablo Almeida
Understood. Thank you!
– Guilherme Santana De Souza
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)
– Maurício Z.B