Pular para o conteúdo

O regex que tira tag HTML devolve 13 vezes mais texto do que existe — e 84% é JavaScript

A conta de uma linha que todo mundo cola para tirar HTML de um texto não devolve texto sujo. Em 35 páginas brasileiras de verdade, ela devolve 13,7× mais caracteres do que a página tem — e 84% do que sai é JavaScript e CSS, não frase.

As 35 páginas, medidas contra um navegador de verdade

Cada página foi baixada em 13 de agosto de 2026 e lida por um Chromium 151: o texto certo é o que o parser do próprio navegador entrega, com <script> e <style> fora. Depois o mesmo HTML passou pelo one-liner. Estas são as doze piores; a conta de todas as 35 está embaixo da tabela.

PáginaTexto certoO que o regex devolveQuantas vezes maior
Sebrae274147.998540,1×
Nubank4.294972.349226,4×
Banco do Brasil36381.705225,1×
Americanas754136.145180,6×
Anvisa3.171512.238161,5×
Estadão16.3011.095.89767,2×
R728.2221.444.98251,2×
Vakinha1.15456.91549,3×
CNN Brasil12.999619.83247,7×
Petrobras9.684430.17844,4×
Mercado Livre6.198272.39643,9×
G115.076617.97641×

Somando as 35: 17.216.492 caracteres de HTML, 603.776 de texto de verdade e 8.269.910 devolvidos pelo one-liner. Nas mesmas páginas, a ferramenta desta casa devolve 1,003× o texto do navegador.

O defeito não é sujeira, é código inteiro

A intuição de quem cola texto.replace(/<[^>]*>/g, "") é que o resultado sai um pouco torto: um espaço a mais, uma quebra fora do lugar. O que sai é outra coisa. Das 8.115.743 letras de JavaScript e CSS que existem dentro de <script> e <style> nas 35 páginas, 7.721.397 sobrevivem à limpeza — 95,1% — e saem no meio do texto. Isso acontece em 35 das 35 páginas medidas, sem uma exceção sequer.

A razão está no que <script> é: não é uma tag comum. O conteúdo dela é texto cru — JavaScript —, e todo < que aparece ali dentro (uma comparação if (a<b), por exemplo) é um sinal de menor, não uma tag abrindo. O regex não sabe disso. Ele vê o < da comparação, procura o > mais próximo, apaga o pedaço no meio e devolve o resto:

entra:  <script>var a=1;if(a<2){console.log("ok")}</script>Total: R$ 10
regex:  var a=1;if(aTotal: R$ 10
aqui:   Total: R$ 10

O JavaScript vaza e sai cortado ao meio. Numa página real, onde o script tem dezenas de milhares de letras, é isso multiplicado por cada bloco — e é por isso que o pior caso do corpus, o Sebrae, devolve 147.998 caracteres para uma página que tem 274 de texto.

A ordem dos três defeitos está errada — inclusive a nossa

A página desta ferramenta lista três jeitos de o one-liner quebrar, e o primeiro que ela cita é o < solto em texto comum: em "5 < 10 and 20 > 15" não há tag nenhuma, e o regex apaga "10 and 20" inteiro. A medição desmontou essa ordem. Nas 35 páginas, o < solto aparece 3 vezes em 17.216.492 caracteres, e o total de texto de verdade que o regex apaga por causa dele é de 5 caracteres. Praticamente zero.

O motivo é simples e não desmente o defeito: quem publica HTML escreve &lt;, porque um < cru na página quebraria a página. Esse defeito não mora no HTML que você copia de um site — mora no texto que você cola: um trecho de código, uma fórmula, um e-mail, uma mensagem com uma comparação matemática. Ele continua real; só não é o que acontece quando a origem é uma página publicada.

O separador de trilha que vira aspas soltas na tela

O segundo defeito, sim, aparece em página publicada: um > dentro das aspas de um atributo. O regex acha que a tag terminou ali e devolve o resto da tag como texto visível. Foram 337 ocorrências em 4 das 35 páginas, e o exemplo mais bonito é o menu do TechTudo, que guarda a trilha de navegação num atributo, com o > de separador que gente escreve:

entra:  <li data-track-click="últimas notícias > notícias">…<span>notícias</span></li>
regex:   notícias">notícias
aqui:   notícias

Repare no que sobra: um pedaço do atributo, com a aspa e o sinal de maior colados, no meio do texto que a pessoa vai ler. Na mesma página do TechTudo isso se repete em cada item do menu.

Tudo isso está escrito na norma, com nome e número

Nenhum dos três casos é ambíguo ou "depende do navegador". O HTML Standard do WHATWG descreve o leitor de HTML como uma máquina de estados, e cada defeito tem um parágrafo com nome e número:

  • 13.2.5.1 Data state — fora de uma tag, só o < muda de estado. O > cai em Anything else: Emit the current input character as a character token, ou seja, é texto. É por isso que procurar o > mais próximo é a pergunta errada.
  • 13.2.5.6 Tag open state — depois de um <, só letra, !, / ou ? abrem alguma coisa. Qualquer outro caractere é invalid-first-character-of-tag-name parse error. Emit a U+003C LESS-THAN SIGN character token — o sinal de menor volta a ser texto.
  • 13.2.5.4 Script data state — dentro de <script> o < vai para um estado próprio, que só reconhece o fechamento daquele mesmo elemento. Comparação dentro de código nunca abre tag.

O removedor desta casa é um scanner que segue essas regras — por isso ele devolve 1,003× o texto do navegador em vez de 13,7×.

O código dos concorrentes, lido na origem

Não é suposição sobre como esses sites costumam funcionar. Em 13 de agosto de 2026, as páginas dos concorrentes desta busca foram baixadas com curl, sem login, e o JavaScript de cada uma foi lido. Três delas — editorfacil.com, tools.iremar.net e cybertools.bitflan.com — servem exatamente o mesmo script, a função window.bitflanToolHtmlTagsComponent, com esta linha dentro:

stripTags() {
  this.content = this.content.replace(/<\/?[^>]+(>|$)/g, "");
}

É um produto white-label revendido, e o defeito viaja junto: a mesma linha atende três endereços diferentes. rocktools.com.br e devbox.tools também terminam num regex — o primeiro converte </p>, <br>, </tr> e </li> em quebra de linha antes, o que melhora o parágrafo e não muda nada quanto ao script que vaza.

E um acerta, o que este artigo faz questão de dizer: devtulz.com usa new DOMParser(), remove script, style e lê textContent — que é, letra por letra, a mesma régua usada para medir todo mundo aqui. Quem escreve JavaScript no navegador tem esse caminho de graça, e ele é melhor que qualquer regex.

Tirar tag não é sanitizar — e isto vale para esta ferramenta também

Falta dizer o que nenhuma dessas páginas diz: o texto que sai daqui serve para ler, nunca para republicar como HTML. Se você pega a saída e joga num innerHTML, você pode estar reconstruindo exatamente a tag que acabou de tirar — e essa não é uma preocupação teórica. A CVE-2026-46361, publicada em maio de 2026 contra o phpMyFAQ, é isso e nada além disso: o conteúdo passava por strip_tags() e depois por html_entity_decode(), e a decodificação restaura as tags cruas — contornando o strip_tags(), entregando o ataque ao navegador de todo visitante.

A ordem que essa falha descreve é a MESMA que esta ferramenta usa: ela tira as tags primeiro e decodifica as entidades depois, e a opção "decodificar entidades" vem ligada. Isso é correto para o produto dela, que é texto legível — quem cola &amp; quer ver & —, e é perigoso se alguém tratar esse texto como HTML seguro. Não é: um &lt;script&gt; colado aqui sai como <script>, por desenho e com teste que cobra isso. Para sanitizar HTML que vai voltar para uma página existe outra categoria de ferramenta, e ela roda no seu servidor, não numa aba.

O que este artigo não mede

O corpus é de páginas públicas, baixadas num dia específico: um site muda o HTML quando quiser, e o que está aqui é o que respondeu em 13 de agosto de 2026. Quatro endereços recusaram o download e ficaram de fora, nomeados em vez de escondidos — Magazine Luiza (HTTP 403), Casas Bahia (HTTP 403), Itaú (HTTP 403), Caixa (HTTP 302 sem corpo). Não medimos e-mail em HTML, que é o outro texto que se cola numa ferramenta dessas, nem nada atrás de login.

Sobre a nossa própria diferença de 1,003×: ela é quase toda uma coisa só, e é conhecida. O gabarito lê o <body>, e o <title> mora no <head> — em 30 das 35 páginas a diferença é exatamente o título da aba, caractere por caractere. Nós devolvemos o texto inteiro que você colou, o navegador devolve o corpo do documento. Em nenhuma das 35 a ferramenta devolveu menos texto que o navegador, e há uma trava no build que derruba a publicação se isso mudar: sobra a mais é escolha, falta seria perda.