Como gerar slug de URL a partir de texto com acentos

O slug é o trecho legível da URL que vem do título, como acao-e-reacao para "Ação e Reação". Para gerá-lo, é preciso tirar os acentos, passar para minúsculas e trocar o resto por hífens. Este guia mostra como fazer isso em JavaScript, Python e PHP com o mesmo resultado, e os cuidados com slugs repetidos, tamanho e mudanças depois de publicar.

Por Leonardo Gaertner · Publicado em

Por que não deixar os acentos na URL

Uma URL pode ter acentos, mas eles viajam codificados: ação vira a%C3%A7%C3%A3o, como mostra o codificador de URL. Ao copiar e colar o endereço, muita gente vê a forma codificada, que fica ilegível. Um slug só com letras sem acento, números e hífens é curto, legível e funciona igual em qualquer lugar.

Como tirar os acentos

O truque é a normalização Unicode NFD, que separa cada letra acentuada em duas partes: a letra e o acento. é vira e seguido do acento agudo, e ç vira c seguido da cedilha. Depois é só remover os acentos separados, que ficam na faixa \u0300 a \u036f. Para gerar slugs sem programar, use o gerador de slug. Para testar com um texto qualquer, use a ferramenta de remover acentos, e para converter nomes em kebab-case ou snake_case, o conversor de maiúsculas e minúsculas.

  • Passe para minúsculas.
  • Troque tudo que não for letra ou número por hífen, juntando sequências (espaços, pontuação, emojis).
  • Tire os hífens das pontas.
JavaScript
function gerarSlug(texto) {
  return texto
    .normalize('NFD') // separa a letra do acento: "é" vira "e" + "´"
    .replace(/[̀-ͯ]/g, '') // remove os acentos
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-') // o resto (espaços, pontuação) vira hífen
    .replace(/^-+|-+$/g, ''); // sem hífen nas pontas
}

// gerarSlug('Ação & Reação: o básico!') === 'acao-reacao-o-basico'

Em Python e PHP

As duas versões fazem a mesma normalização e dão o mesmo resultado do JavaScript. No PHP, a classe Normalizer vem da extensão intl. Evite iconv com //TRANSLIT: o resultado muda conforme o sistema do servidor.

Python
import re
import unicodedata


def gerar_slug(texto: str) -> str:
    # NFD separa a letra do acento; combining() identifica o acento separado
    decomposto = unicodedata.normalize("NFD", texto)
    sem_acento = "".join(c for c in decomposto if not unicodedata.combining(c))
    return re.sub(r"[^a-z0-9]+", "-", sem_acento.lower()).strip("-")
PHP
<?php
// Requer a extensão intl (Normalizer), que vem na maioria das instalações
function gerarSlug(string $texto): string
{
    $decomposto = Normalizer::normalize($texto, Normalizer::FORM_D);
    $semAcento = preg_replace('/\p{Mn}/u', '', $decomposto); // \p{Mn}: os acentos
    return trim(preg_replace('/[^a-z0-9]+/', '-', mb_strtolower($semAcento)), '-');
}

Cuidados

  • Slugs repetidos: dois títulos iguais geram o mesmo slug. Antes de salvar, confira no banco e acrescente um número (-2, -3), ou use um índice único na coluna.
  • Tamanho: corte em uns 60 a 80 caracteres, de preferência no último hífen, para não partir uma palavra no meio.
  • Não mude o slug depois de publicar. Se precisar mudar, redirecione o endereço antigo para o novo com o código 301, para não perder os links e a posição nas buscas.
  • Letras que não são uma letra comum com acento, como ß e ø, não se decompõem e viram hífen. Para outros idiomas, use uma biblioteca de transliteração.

Achou um erro neste guia? Avise por e-mail.

Perguntas frequentes

Como remover acentos de um texto em JavaScript?

Use texto.normalize("NFD").replace(/[\u0300-\u036f]/g, ""). O NFD separa a letra do acento, e o replace remove os acentos, deixando as letras.

O que é um slug?

É a parte legível da URL que identifica a página, normalmente gerada a partir do título: só letras minúsculas sem acento, números e hífens, como como-gerar-slug.

Posso usar acentos na URL?

Pode, mas eles são enviados codificados, como %C3%A7 no lugar de ç, e o endereço fica difícil de ler quando copiado. Por isso a maioria dos sites usa slugs sem acento.

Como evitar slugs repetidos?

Confira se o slug já existe antes de salvar e, se existir, acrescente um número no fim. Uma restrição de valor único no banco garante que dois registros não fiquem com o mesmo slug.