Decodificare le entità HTML

Incolla del testo con dentro dei riferimenti di carattere e leggi cosa dice. Vengono riconosciuti quelli con nome, quelli decimali e quelli esadecimali. Conta di più come viene fatto: con una tabella e non infilando il tuo testo dentro un elemento per chiedere al browser — è quella differenza a decidere se del markup altrui possa fare qualcosa mentre lo decodifichi.

Risultato

La risposta compare qui mentre scrivi.

  • Dove gira

    Non viene caricato nulla, perché non c’è nessun file: il calcolo avviene in questa pagina.

  • Nessuna coda, nessun account

    Risponde alla velocità della tua macchina e non chiede mai chi sei.

  • Tutte le volte che vuoi

    Non si conta né si limita nulla: rispondere di nuovo non ci costa niente.

Come funziona

  1. Incolla il testo con i riferimenti di carattere.
  2. Leggi il risultato. Quello che non viene riconosciuto o è incompleto resta com’è, invece di sparire in silenzio.
  3. Copia quello che ti serve. Non è stato caricato niente.

Con una tabella, e non con un parser

Il modo più corto di decodificare delle entità in una pagina web è assegnare il testo all’`innerHTML` di un elemento e rileggerne il contenuto. Funziona, ed è il motivo per cui compare in tanti esempi. Vuol anche dire dare del markup altrui a un parser HTML vero, dentro la pagina che stai usando.

Un parser HTML non si limita a costruire un albero: un `<img src=x onerror=...>` esegue, e un tag con un indirizzo remoto provoca una richiesta di rete che dice a un terzo che quel testo è stato incollato qui. Questa pagina usa invece una tabella di corrispondenze e non costruisce nessun elemento, il che rende l’intera categoria di problemi impossibile invece che improbabile.

Tre forme che compaiono tutte

Lo stesso carattere si scrive con un nome — `&amp;` —, in decimale — `&#38;` — o in esadecimale — `&#x26;`. Vengono riconosciute tutte e tre, e non è una comodità: in un testo reale compaiono mescolate, perché sono passate per sistemi diversi in momenti diversi.

La forma numerica è quella che si trova nei feed RSS rigorosi e nei documenti XML, dove i nomi definiti sono soltanto cinque. Quella con nome è più comune nell’HTML scritto a mano. Un testo che le contiene entrambe ha attraversato almeno due strumenti, e spesso questa è già l’informazione utile su come è stato costruito.

Il punto e virgola che manca

Un riferimento di carattere finisce con un punto e virgola. Senza, il testo non è più un riferimento: `&amp` senza chiusura resta quattro caratteri normali, e qui viene restituito così com’è invece di essere indovinato.

I browser sono più permissivi: per un elenco chiuso di entità storiche accettano anche la forma senza punto e virgola, ed è la ragione per cui una pagina rotta si vede lo stesso mentre uno strumento severo segnala un problema. Restituire il testo intatto è la scelta più utile in un decodificatore, perché mostra che qualcosa a monte ha troncato la stringa invece di nasconderlo.

Perché a volte bisogna decodificare due volte

Se dopo la decodifica trovi ancora `&lt;` o `&amp;`, il testo era stato protetto due volte. È la stessa dinamica della doppia codifica percentuale, con altri caratteri: un valore protetto da un framework e riprotetto da un template, oppure un contenuto già protetto salvato in un database e riprotetto al momento di mostrarlo.

Decodificare ancora una volta risolve il sintomo. Vale però la pena capire dove nasce, perché la doppia protezione ha un fratello peggiore: se il testo viene protetto due volte in uscita e decodificato una volta all’ingresso, il conto non torna mai e il difetto si sposta a ogni salvataggio, allungando la catena di `&amp;amp;` un pezzo alla volta.

Da dove arrivano le entità doppie

La sorgente più comune è un contenuto passato per un editor visuale e poi per un template. L’editor salva il testo già protetto, il template lo protegge di nuovo perché non ha modo di sapere che lo era, e il risultato è un `&amp;amp;` che nella pagina si legge come `&amp;`.

La seconda sorgente sono i feed. Un feed RSS trasporta HTML dentro XML, quindi il contenuto viene protetto una volta per l’HTML e una per l’XML: chi legge il feed con uno strumento che decodifica un solo strato vede le entità, e chi le decodifica tutte e due vede il markup. Nessuno dei due comportamenti è sbagliato, il che è precisamente il problema.

Più di duemila nomi, e la lista è chiusa

L’HTML definisce oltre duemila riferimenti con nome, molti più dei quattro o cinque che si incontrano di solito: ci sono lettere greche, simboli matematici, frecce e segni di valuta. La lista è però chiusa e non si può estendere, quindi un nome inventato non è un carattere sconosciuto ma semplicemente del testo.

La conseguenza pratica riguarda i valori che sembrano entità e non lo sono. Un testo che contiene `R&D` seguito da una parola può assomigliare a un riferimento e non lo è, e uno strumento che lo trasformasse in qualcosa produrrebbe un guasto silenzioso. Qui resta quello che è, che è l’unico comportamento difendibile.

Riferimenti numerici oltre il piano base

I riferimenti numerici indicano un punto di codice Unicode e non un byte, quindi arrivano anche molto oltre il repertorio latino: `&#128512;` è un emoji, e in UTF-16 quel carattere occupa due unità. È il motivo per cui contare i caratteri di una stringa che li contiene dà risultati diversi a seconda del linguaggio.

Un caso specifico da riconoscere è la coppia surrogata scritta come due riferimenti separati, che nasce da sistemi che hanno tagliato il testo per unità e non per caratteri. Presi singolarmente non sono caratteri validi, e una decodifica corretta li lascia stare: se nel risultato compaiono simboli isolati e strani, il taglio è avvenuto prima e non qui.

Lo spazio che non si vede

`&nbsp;` è U+00A0, lo spazio unificatore: sullo schermo è indistinguibile da uno spazio normale e per qualunque programma è un altro carattere. Dopo la decodifica è invisibile, ed è la causa più frequente di due stringhe che sembrano uguali e non lo sono.

I danni tipici sono tre: un confronto che fallisce, una ricerca che non trova niente, e un `trim` che non toglie quello spazio perché non è uno spazio. Se un testo decodificato non si comporta come dovrebbe, la pagina di codifica esadecimale di questo sito lo mostra subito — `c2 a0` è lo spazio unificatore, `20` è quello normale.

Testo altrui, che resta dov’è

Il materiale che arriva a un decodificatore di entità viene quasi sempre da un campo di database, da un export di uno scraper o da un feed: contenuti scritti da persone, spesso con dentro nomi e indirizzi. Su un servizio remoto sarebbe una comunicazione di dati altrui a un terzo, decisa da chi sta solo cercando di leggere una stringa.

Qui non succede, perché la tabella di corrispondenze sta nella pagina e il conto dura un istante. La stessa decisione ha un secondo effetto: siccome non viene costruito nessun elemento e non parte nessuna richiesta, nemmeno il markup che stai decodificando può segnalare a qualcuno che qualcuno lo sta guardando.

Decodificare le entità HTML: domande frequenti

Perché nel risultato compare ancora &lt;?

Perché il testo era stato protetto due volte. Decodifica ancora una volta e otterrai il carattere. Vale la pena risalire alla causa: di solito è un editor visuale che salva il contenuto già protetto e un template che lo protegge di nuovo, e la catena di &amp; si allunga a ogni salvataggio.

Perché &amp senza punto e virgola non viene risolto?

Perché senza punto e virgola non è un riferimento di carattere. I browser accettano lo stesso una lista chiusa di forme storiche, ed è per questo che una pagina rotta si vede comunque. Qui il testo resta com’è, il che rende visibile che qualcosa a monte ha troncato la stringa.

Del markup altrui può fare qualcosa in questa pagina?

No, e non per prudenza ma per costruzione: la decodifica usa una tabella di corrispondenze e non costruisce nessun elemento. Gli strumenti che assegnano il testo all’innerHTML danno il tuo markup a un parser vero, che può eseguire un onerror o provocare una richiesta verso un dominio esterno.

Cos’è il carattere invisibile che esce da &nbsp;?

È U+00A0, lo spazio unificatore: sullo schermo sembra uno spazio, per un confronto di stringhe è un altro carattere. È la causa abituale di una ricerca che non trova niente e di un trim che non toglie niente. Nella pagina di codifica esadecimale si riconosce subito, perché è `c2 a0` invece di `20`.

Il testo esce dalla mia macchina?

No. La tabella sta nella pagina e la decodifica avviene nella scheda, quindi non parte nessuna richiesta. Conta perché il testo che si decodifica arriva quasi sempre da un database o da un feed e contiene parole scritte da altre persone.

Altri strumenti