Vai al contenuto
OneKitly

Che cosa deve decidere un verificatore di palindromi prima di poter rispondere

Pubblicato il 02/06/2025 · 12 min di lettura · Strumenti testo e lingua

Daniel Okonkwo

Daniel OkonkwoSviluppatore front-end e redattore Tech presso OneKitly

Performance web · Formati di file

Verificato su 5 fonti

Vedi il profilo
In breve

«È un palindromo?» non ha risposta finché non sono state prese quattro decisioni di normalizzazione, e ognuna cambia il verdetto su frasi reali. Eseguito in Node: «I topi non avevano nipoti» non è un palindromo così com'è, ma lo diventa già togliendo maiuscole e spazi, senza bisogno di alcuna regola sulla punteggiatura. L'inglese «A man, a plan, a canal: Panama» si ferma un gradino più in là: gli servono maiuscole, spazi e punteggiatura. Il tedesco «Ein Esel lese nie» è già un palindromo con le sole maiuscole, perché i suoi spazi cadono simmetricamente. E il francese «Ésope reste ici et se repose», lo spagnolo «Dábale arroz a la zorra el abad» e il portoghese «Socorram-me, subi no ônibus em Marrocos» richiedono una quarta regola, il ripiegamento dei segni diacritici, perché É ed e sono caratteri diversi. La seconda metà del problema è che invertire una stringa non è di per sé definito. Invertire per unità di codice UTF-16 spezza le coppie surrogate e produce testo non ben formato; invertire per punto di codice stacca un accento combinante dalla sua lettera. Inverti per gruppo di grafemi, con Intl.Segmenter, e dichiara le quattro politiche.

Maiuscole, spazi, punteggiatura e segni diacritici: quattro politiche, sei frasi reali, e la risposta cambia con ciascuna. Poi la metà più difficile — invertire una stringa non è di per sé definito, e l'inversione per unità di codice rompe le emoji e stacca gli accenti, dimostrato in Node.

La domanda è indefinita finché non si prendono quattro decisioni

Un palindromo si legge uguale nei due sensi. Quella definizione è completa solo per una sequenza di minuscole nude, e quasi nessun testo reale lo è. Appena una frase ha maiuscole, spazi, virgole o accenti, la domanda si spezza in quattro: una maiuscola equivale alla sua minuscola, gli spazi contano come caratteri, conta la punteggiatura, e una lettera accentata è la stessa lettera della sua base? Quattro risposte sì o no, sedici combinazioni, e quelle che contano formano una sequenza annidata, ciascuna che ammette più frasi della precedente.

La tabella qui sopra è quella sequenza applicata a sei frasi, eseguita anziché discussa. Leggila colonna per colonna e ogni colonna si guadagna il posto: gli spazi da soli promuovono la frase italiana, la punteggiatura da sola promuove quella inglese, e il ripiegamento degli accenti da solo promuove la francese, la spagnola e la portoghese. Un verificatore che fissa una qualsiasi di queste scelte sta rispondendo a una domanda diversa da quella posta dal suo utente, e la risponde in silenzio.

Quattro frasi, quattro punti d'arresto diversi

Cominciamo dall'inglese, perché è la frase che tutti citano. «A man, a plan, a canal: Panama» non è un palindromo così com'è: la A maiuscola di un capo fronteggia una a minuscola dall'altro. Ripiega le maiuscole e ancora non lo è: gli spazi non cadono simmetricamente. Togli gli spazi e ancora non lo è, perché restano una virgola e due punti. Togli anche la punteggiatura e finalmente lo è: amanaplanacanalpanama, ventun caratteri, simmetrico. Tre politiche hanno dovuto essere attivate prima che comparisse la risposta famosa.

La tedesca «Ein Esel lese nie» si ferma un gradino prima di tutto il resto della tabella. Ripiega le maiuscole ed è già un palindromo: einesellesenie si legge uguale nei due sensi, e anche la frase con i suoi spazi al loro posto, perché le sue lunghezze di parola — tre, quattro, quattro, tre — sono simmetriche per costruzione. Un verificatore che toglie sempre gli spazi indovina qui, ma per la ragione sbagliata, e non potrà mai dirti che questa frase è un palindromo nel senso più forte in cui lo sono anche i suoi spazi. L'altro esempio tedesco, «O, Genie, der Herr ehre dein Ego!», ha bisogno solo della regola sulla punteggiatura.

Le tre frasi romanze richiedono tutte la quarta regola e falliscono a ogni regola precedente. «Ésope reste ici et se repose», con la punteggiatura tolta ma gli accenti conservati, dà ésoperesteicietserepose, il cui inverso è esoperesteicietsereposé: l'accento è migrato dal primo carattere all'ultimo, e le stringhe differiscono. Ripiega il segno diacritico ed entrambe diventano esoperesteicietserepose. Lo stesso accade con dábale…, il cui inverso finisce in á, e con socorram-me…, dove la ô atterra nel posto sbagliato. Nota che cosa implica: un verificatore costruito per l'inglese dichiarerà falliti tre palindromi europei perfettamente validi, e lo farà senza alcun messaggio di errore.

Nemmeno invertire una stringa è una sola operazione

Ogni verificatore di palindromi confronta un testo con il suo inverso, ed è in quell'inverso che vive la seconda metà del problema. L'inversione in una riga che tutti scrivono — s.split('').reverse().join('') — inverte unità di codice UTF-16. Un articolo compagno di questa serie tratta di che cosa sia un carattere; la conseguenza qui è che ogni carattere fuori dal piano multilingue di base è memorizzato su due unità di codice, e invertirle singolarmente scambia la coppia. Inverti «ça va 😀» così e il risultato contiene un surrogato basso seguito da uno alto: otto punti di codice invece di sette, e isWellFormed() restituisce falso. Sullo schermo è un quadratino di sostituzione.

Il rimedio abituale è invertire i punti di codice: [...s].reverse().join(''). Ripara l'emoji — «ça va 😀» diventa «😀 av aç», ancora sette punti di codice — e ancora non basta. Prendi «José» in forma decomposta, dove la é è una e seguita da un accento acuto combinante: cinque punti di codice, quattro grafemi. Invertire i punti di codice mette l'accento combinante in testa, dove non ha più una lettera a cui attaccarsi, e lascia una e nuda: il risultato ha cinque grafemi dove ce n'erano quattro, e l'accento si disegna sul nulla. Il caso tedesco è ancora più vistoso. Decomponi «Grüße» e inverti i suoi punti di codice e ottieni eß̈urG: la dieresi è saltata dalla u ed è atterrata sulla ß.

Le emoji composte da più punti di codice falliscono allo stesso modo. La famiglia 👨‍👩‍👧 sono tre persone unite da giuntori a larghezza zero: sedici unità di codice, tredici punti di codice, un solo grafema. Invertire i suoi punti di codice produce una famiglia che si disegna 👧‍👩‍👨 — figlia, madre, padre —, cioè un'altra emoji, non una invertita; invertire le sue unità di codice produce qualcosa che si disegna a frammenti. Solo l'inversione per gruppo di grafemi la lascia intatta.

Invertire per gruppo di grafemi

Un gruppo di grafemi è il nome che Unicode dà a ciò che un lettore chiama un carattere: una lettera base più tutto ciò che vi si combina, o un'intera sequenza emoji. JavaScript espone le regole di segmentazione direttamente tramite Intl.Segmenter, e un'inversione corretta sta in tre righe: costruire un segmentatore con granularità «grapheme», distendere il suo output, invertire, unire. Su tutti gli esempi qui sopra fa la cosa giusta: l'emoji sopravvive, la famiglia resta una famiglia, e il Grüße decomposto torna come eßürG, con la dieresi ancora sulla sua u.

Sotto si nasconde una decisione di normalizzazione, e la parola francese été la rivela in una riga. In forma composta sono tre punti di codice e invertirli restituisce été: palindromo. In forma decomposta sono cinque punti di codice, invertirli dà una stringa con gli accenti fuori posto, e la stessa parola visibile viene dichiarata non palindroma. L'inversione per gruppo di grafemi dà la risposta giusta in entrambe le forme — ma se confronti le due forme fra loro restano diverse, ed è per questo che un verificatore dovrebbe normalizzare in NFC prima di ogni altra cosa. L'articolo di questa serie dedicato agli accenti tratta per esteso le forme NFC e NFD.

Un palindromo numerico è un altro problema

I numeri sembrano il caso facile e non lo sono. Un palindromo numerico è una proprietà di un valore in una base; un palindromo testuale è una proprietà di una resa. 12321 è un palindromo in base dieci. Reso per un lettore smette di esserlo in ogni locale di questo articolo: 12,321 invertito dà 123,21 in inglese, 12.321 invertito dà 123.21 in tedesco, spagnolo e italiano, e 12 321 invertito dà 123 21 in francese e portoghese — dove il separatore è uno spazio unificatore stretto U+202F in francese e uno spazio unificatore normale U+00A0 in portoghese, due caratteri invisibili che un confronto ingenuo tratterà comunque come diversi.

Dalla stessa distinzione discendono altre tre differenze. Un segno è un carattere ma non una cifra: -121 come testo si inverte in 121- e fallisce, mentre come valore la questione se un numero negativo possa essere palindromo è una convenzione da scegliere. Un separatore decimale è ugualmente un carattere: 0,1 si inverte in 1,0, due stringhe diverse che denotano valori diversi. E gli zeri iniziali esistono nel testo e non nei numeri: 010 è palindromo come testo, e come numero è 10, che non lo è. Se il tuo input è un numero, togli la formattazione e lavora sulle cifre; se è un testo che sembra numerico, dillo e trattalo come testo.

Che cosa costruire, in ordine

La ricetta che sopravvive a tutte e sei le lingue è corta. Normalizza prima in NFC, così che lo stesso testo visibile abbia sempre la stessa rappresentazione. Applica poi le politiche che hai deciso e sai nominare: minuscole, togliere gli spazi, togliere tutto ciò che non è lettera o cifra, ripiegare gli accenti decomponendo e rimuovendo i segni. Poi inverti per gruppo di grafemi e confronta. Quattro passaggi, e ognuno è una scelta che puoi mostrare nell'interfaccia invece di un valore predefinito nascosto nel codice.

Un'ultima osservazione sull'inversione, perché è controintuitiva e nasconde bug. Invertire due volte restituisce sempre la stringa originale, qualunque sia l'unità scelta: unità di codice, punti di codice e grafemi sono tutti involuzioni sulla sequenza su cui operano. Quindi un test di andata e ritorno non ti dice nulla sulla correttezza della tua inversione. L'unico test che intercetta i casi rotti è guardare il risultato intermedio, e il modo più rapido di guardarlo è contare i grafemi prima e dopo: per un José decomposto sono quattro e poi cinque.

Sei frasi sotto quattro politiche cumulative, eseguite in Node 26.3. Ogni colonna aggiunge una regola alla precedente, e ogni colonna cambia almeno un verdetto — che è tutto l'argomento: «palindromo» non è una proprietà di un testo, ma di un testo più una politica.
FraseSolo maiuscole ripiegate+ spazi ignorati+ punteggiatura ignorata+ accenti ripiegati
A man, a plan, a canal: PanamaNoNo
I topi non avevano nipotiNo
Ein Esel lese nie
Ésope reste ici et se reposeNoNoNo
Dábale arroz a la zorra el abadNoNoNo
Socorram-me, subi no ônibus em MarrocosNoNoNo
Verificatore di palindromiVerifica se il tuo testo si legge uguale in entrambi i sensi.Prova lo strumento

Domande frequenti

«A man, a plan, a canal: Panama» è un palindromo oppure no?
Con la politica abituale sì; così com'è scritto no. Ripiega le maiuscole, togli gli spazi e togli la punteggiatura e diventa amanaplanacanalpanama, che è simmetrico. Conserva uno qualsiasi dei tre e non lo è. Non è una domanda trabocchetto: è esattamente ciò che fa la formula «ignorando maiuscole, spazi e punteggiatura» di ogni definizione da manuale, e uno strumento che lascia attivare le tre regole separatamente dice la verità invece di nasconderla.
Perché invertendo il mio testo è comparso un quadratino rotto?
Perché l'inversione ha lavorato su unità di codice UTF-16 e il tuo testo conteneva un carattere fuori dal piano multilingue di base: un'emoji, un ideogramma CJK raro, un simbolo matematico. Quelli sono memorizzati come coppia surrogata, e invertirne le due metà produce una sequenza che nessun font sa disegnare. Verificalo con isWellFormed(), che restituisce falso su una stringa simile, e passa l'inversione ai gruppi di grafemi con Intl.Segmenter.
Un verificatore di palindromi deve ignorare gli accenti?
Dovrebbe offrire la scelta e ripiegare per impostazione predefinita, perché la tradizione del gioco di parole in francese, spagnolo e portoghese tratta é ed e come la stessa lettera. Senza ripiegamento, tre delle sei frasi della tabella smettono di essere palindromi: «Ésope reste ici et se repose», «Dábale arroz a la zorra el abad» e «Socorram-me, subi no ônibus em Marrocos» falliscono tutte sul primo e sull'ultimo carattere. Ripiega decomponendo in NFD, cancellando i segni combinanti e ricomponendo — l'articolo di questa serie sugli accenti spiega perché non è la stessa cosa che sostituire lettere una per una.
12321 è un palindromo?
Come numero in base dieci, sì. Come testo visualizzato, no — in ogni locale di questo articolo. Formattato per un lettore diventa 12,321 in inglese e 12.321 o 12 321 altrove, e invertire quelle stringhe dà 123,21, 123.21 e 123 21. Se verifichi numeri, lavora sulle cifre e decidi esplicitamente che fare con un segno, un separatore decimale e gli zeri iniziali: -121 si inverte in 121-, 0,1 si inverte in 1,0, e 010 è palindromo come testo mentre il numero che denota è 10.
Invertire due volte una stringa restituisce sempre l'originale?
Sì, ed è proprio per questo che un test di andata e ritorno qui non vale nulla. Invertire per unità di codice, per punto di codice o per gruppo di grafemi sono tutte involuzioni: applicane una due volte e riottieni l'input, anche quando l'inversione singola ha prodotto nel frattempo una stringa rotta. Verifica invece il risultato intermedio: confronta il numero di grafemi prima e dopo, o chiama isWellFormed() su di esso.
Una singola parola può essere palindroma senza nessuna di queste regole?
Sì, e quelli sono gli unici casi in cui la domanda ha una sola risposta. Le parole interamente in minuscolo ASCII come racecar, radar, kayak, il francese ressasser, lo spagnolo reconocer, l'italiano onorarono e il portoghese reviver sono palindromi senza alcuna politica — verificato carattere per carattere. Mettici una maiuscola e ti serve la regola sulle maiuscole: i tedeschi Reliefpfeiler, Rentner e Lagerregal sono palindromi solo una volta ripiegata la capitale iniziale, il che è una politica e non quattro.

Articoli che potrebbero interessarti

Tutte le guide
SpiegazioneRilevare la lingua di un testo, e perché i testi brevi fallisconoMisurato, non affermato: 90 frasi brevi reali in sei lingue, nessuna rifiutata e 68 giuste — il 76%, che scende al 64% sotto le sedici lettere. Quattro delle risposte sbagliate sono tornate con il 100% di fiducia.SpiegazioneTogliere gli accenti rompe la ricerca — finché non lo fai da entrambi i latiRipiegare i segni diacritici è un passaggio di normalizzazione, e la normalizzazione funziona solo se la stessa funzione gira sull'indice e sulla query. NFC contro NFD con i punti di codice in chiaro, e le lettere — ø, ł, ß, œ, ı — che escono dal ripiegamento intatte.SpiegazioneLe emoji sono più difficili di quanto sembri: perché «basta toglierle» non ha una risposta in una rigaUna emoji visibile può valere un punto di codice o quattordici unità UTF-16. Abbiamo lanciato tre espressioni regolari diffuse su una frase vera e ognuna si è rotta in modo diverso; una ha cancellato le cifre. Ecco perché, quale proprietà Unicode risponde a quale domanda, e la regola a gruppi di grafemi che funziona davvero.TutorialNumerare le righe di un testo per una revisione a più maniLa numerazione parte da 1 e non si può impostare a 0, l'allineamento usa spazi e non zeri, e lo strumento che li toglie annulla otto degli undici separatori senza toccare l'indentazione. Quello che ancora non sa fare è distinguere i tuoi numeri dai suoi.SpiegazioneMaiuscolo di frase e maiuscolo di titolo: le regole cambiano con la linguaIl maiuscolo di titolo inglese ha tre soglie diverse a seconda del manuale di stile. Francese, spagnolo, portoghese e italiano non ne hanno nessuna. Il tedesco scrive maiuscolo ogni sostantivo. Lo strumento non sa nulla di tutto ciò: ecco esattamente cosa fa.TutorialFiltrare righe secondo uno schema, senza riga di comandoQuesto è grep per chi non usa grep, con una differenza importante: la ricerca è una sottostringa letterale, quindi una vera espressione regolare restituisce un riquadro vuoto e nessun errore. Ogni affermazione è stata verificata eseguendo lo strumento.

Strumenti correlati

Fonti

Hai notato un errore in questo articolo?