Decodificar entidades HTML

Cole um texto com referências de caractere e leia o que ele diz. As de nome, as decimais e as hexadecimais são todas reconhecidas. O que importa mais é como isso é feito: com uma tabela, e não colocando o seu texto dentro de um elemento para perguntar ao navegador — essa diferença é a que decide se uma marcação alheia consegue fazer alguma coisa enquanto você a decodifica.

Resultado

A resposta aparece aqui enquanto você digita.

  • Onde roda

    Nada é enviado, porque não há arquivo — a conta é feita nesta página.

  • Sem fila, sem conta

    Responde na velocidade da sua máquina e nunca pergunta quem você é.

  • Quantas vezes quiser

    Nada é contado nem limitado — responder de novo não nos custa nada.

Como funciona

  1. Cole o texto com as referências de caractere.
  2. Leia o resultado. O que não for reconhecido ou estiver incompleto fica como está, em vez de sumir em silêncio.
  3. Copie o que precisar. Nada foi enviado.

Com uma tabela, e não com um parser

O jeito óbvio de resolver entidades é escrever o texto dentro de um elemento e ler o `textContent` dele. É também o jeito pelo qual metade das ferramentas desse gênero abre um buraco: um `<img src=x onerror=...>` dentro do texto vira um elemento de verdade, e dependendo do método aquilo dispara uma requisição de rede ou executa código.

Aqui isso não acontece, porque em nenhum momento HTML é gerado. As referências são resolvidas contra uma tabela e as numéricas são calculadas: não existe ponto em que o seu texto seja interpretado como marcação. E é por isso mesmo que esta página não pode oferecer uma prévia — seria voltar exatamente ao que está sendo evitado.

Três formas que aparecem todas

Uma referência começa com `&` e termina com `;`. No meio vai um nome como `amp` ou `nbsp`, uma cerquilha com um número decimal como `#231`, ou uma cerquilha com `x` e um hexadecimal como `#xE7`. As duas últimas designam o mesmo ponto de código em duas bases.

Na prática as três aparecem no mesmo arquivo, porque foram produzidas por peças diferentes: os gerenciadores de conteúdo tendem às de nome, as exportações às decimais, as ferramentas de XML às hexadecimais. Aqui as três são tratadas igual, então você não precisa saber qual parte da sua esteira tinha qual preferência.

O ponto e vírgula que falta

Os navegadores são generosos: um `&amp` sem ponto e vírgula é resolvido do mesmo jeito em muitos contextos, porque as páginas antigas escreviam assim e a compatibilidade venceu. Essa indulgência está até prevista no padrão do HTML, mas só para uma lista limitada de nomes e não dentro de valor de atributo.

Para você isso significa que um `&amp` sem ponto e vírgula nos seus dados é uma bomba-relógio, porque processadores diferentes tratam de formas diferentes. Esta ferramenta exige o ponto e vírgula e deixa as referências incompletas onde estão: o que fica visível é justamente o lugar em que alguma coisa foi gerada errado.

Por que às vezes é preciso decodificar duas vezes

Se no resultado ainda há um `&lt;`, a entrada estava duplamente codificada: ela continha `&amp;lt;`, e uma passada produz corretamente `&lt;`. Não é um resultado pela metade, é o correto — um decodificador que continuasse até nada mais parecer entidade destruiria também o texto em que `&lt;` estava escrito de propósito.

O jeito limpo é passar o texto de novo sabendo que você está fazendo isso. Se você precisa de duas passadas com frequência, a tarefa real é encontrar a dupla codificação na esteira que gera o dado, e não apertar duas vezes aqui.

De onde vêm as entidades duplas

Quase sempre de um valor que foi guardado escapado e que o motor de template escapou de novo ao mostrar. As duas etapas estão certas separadamente; o que está errado é serem duas. Isso só aparece na página final, onde a pessoa lê `&nbsp;` como texto.

A segunda fonte são importações e migrações: os dados de um sistema antigo chegam já escapados e a rotina nova trata como se viessem crus. Também dá para reconhecer pelo `&amp;` na frente de outros nomes de entidade — é a assinatura de duas camadas sobrepostas.

Mais de dois mil nomes, e a lista está fechada

O HTML5 define mais de 2.200 referências com nome, de `&amp;` e `&copy;` até símbolos matemáticos que quase ninguém escreve. A lista está congelada de propósito: nomes novos não são acrescentados, porque cada acréscimo mudaria documentos que já existem.

Na prática: se um nome não é resolvido aqui, ou ele está escrito errado ou nunca existiu. Caracteres novos já não recebem nome; para tudo o que o Unicode acrescentou desde 2014 só existe a forma numérica. Um `&emoji;` nunca existiu e não vai existir.

Os nomes que sobraram da época do Latin-1

A lista tem nomes para caracteres acentuados — `&ccedil;` para `ç`, `&atilde;` para `ã`, `&eacute;` para `é` — e eles são um resquício de quando um documento não podia carregar esses bytes com segurança. Num documento UTF-8 eles não servem para nada além de dobrar o tamanho do texto.

Onde eles aparecem hoje é revelador: em conteúdo que passou por um gerenciador antigo, numa exportação de banco herdada ou num e-mail gerado por uma biblioteca dos anos 2000. Ver `&ccedil;` num campo é uma pista de idade do dado, e vale mais do que parece quando se está rastreando de onde veio um texto estragado.

Referências numéricas além do plano básico

Os pontos de código acima de `FFFF` — emoji, escritas pouco frequentes, alguns símbolos matemáticos — precisam internamente de duas unidades no JavaScript, um par substituto. Um decodificador que não leve isso em conta produz dois meios caracteres quebrados no lugar de um inteiro.

Às vezes também aparecem referências que escrevem cada metade do par separadamente, porque uma ferramenta antiga codificou assim. Esses valores são Unicode inválido no sentido estrito; aqui eles não são convertidos em silêncio para um caractere de substituição, para que fique visível que o problema está na origem e não na exibição.

O espaço que não se vê

Um `&nbsp;` vira um caractere que parece um espaço e não é: ele tem o ponto de código `A0` em vez de `20`. Por isso depois falha uma comparação, um localizar e substituir ou um `trim()`, sem que haja nada de suspeito na tela.

É a falha mais chata desta família justamente por ser invisível. Quem processa texto copiado de um gerenciador de conteúdo ou de um editor de textos precisa contar com ela: o Word e a maioria dos editores visuais colocam espaço rígido com generosidade. Se dois valores «obviamente iguais» não comparam como iguais, esse é o primeiro lugar para olhar.

Decodificar é o contrário de proteger

Uma coisa que se perde de vista com facilidade: o texto escapado estava protegido justamente porque estava escapado, e decodificar desfaz essa proteção. O resultado desta página é, por definição, mais perigoso do que a entrada dela.

Então isto é uma ferramenta de leitura e não a última etapa de uma esteira que serve HTML. Se o texto decodificado vai voltar para uma página, ele precisa ser escapado de novo para o lugar em que vai parar — e se ele precisa manter parte da marcação, o que resolve é um sanitizador com lista de permissão, não uma volta por aqui.

O e comercial que separa dois parâmetros num href

Dentro de um documento HTML, o `&` que separa dois parâmetros de uma URL deveria estar escrito como `&amp;`, porque no HTML ele abre uma referência de caractere. Um endereço escrito com `&` puro funciona na maioria dos casos, e falha exatamente quando o que vem depois é um nome de entidade conhecido.

Daí que decodificar o valor de um `href` copiado do código-fonte é um passo legítimo antes de usá-lo: o que estava escrito era HTML, e a URL de verdade é o resultado. E daí também que ver `&amp;` na barra de endereço do navegador é sinal de que alguma coisa decodificou uma vez a menos no caminho.

Texto de terceiros no campo, e a LGPD

Chega com frequência a este campo texto de terceiros: um extrato de banco de dados, um chamado de suporte, uma entrada de feed com nomes e endereços dentro. Como a resolução acontece na página, nada disso é compartilhado conosco nem gera tratamento da nossa parte.

Vale lembrar também que o texto decodificado é, por definição, menos inofensivo do que o escapado. Quem for devolvê-lo a uma página precisa escapar de novo para o destino; esta é uma ferramenta de leitura, e é assim que ela deve ser encaixada na esteira.

Decodificar entidades HTML: perguntas frequentes

Por que ainda aparece &lt; no resultado?

Porque a entrada estava duplamente codificada: ela continha &lt; e uma passada produz corretamente <. Passe de novo se for isso que você quer, e depois procure na esteira que gera o dado a etapa que escapa duas vezes.

Por que &amp sem ponto e vírgula não é resolvido?

Porque sem o ponto e vírgula a referência não é inequívoca. Os navegadores são indulgentes por compatibilidade, mas não de forma uniforme; aqui ela fica como está para que se veja onde alguma coisa foi gerada errado.

Uma marcação alheia consegue fazer alguma coisa aqui?

Não. As referências são resolvidas contra uma tabela e as numéricas são calculadas; em nenhum momento HTML é gerado. É por isso mesmo que também não existe prévia renderizada.

Que caractere invisível é esse que sai de &nbsp;?

Um espaço rígido com o ponto de código A0. Ele parece um espaço normal mas é outro caractere, então comparações, localizar e substituir e funções de corte não o tratam como espaço em branco.

O texto sai do meu aparelho?

Não. Tudo acontece nesta página; não há servidor nenhum decodificando. O painel de rede confirma isso enquanto você digita.

Outras ferramentas