Expressões regulares com preg
Expressões regulares (regex) são padrões de busca e manipulação de texto extremamente poderosos. No PHP, a família de funções preg_* implementa o PCRE (Perl Compatible Regular Expressions), oferecendo ferramentas robustas para validação, extração, substituição e divisão de strings. Diferentemente de implementações mais simples como ereg (obsoleta), o PCRE oferece sintaxe moderna, alta performance e suporte completo a metacaracteres e modificadores.
As principais funções são: preg_match(), preg_match_all(), preg_replace(), preg_replace_callback(), preg_split() e preg_grep(). Cada uma atende a um propósito específico no processamento de strings.
Sintaxe Básica de Padrões em PHP
Todo padrão regex em PHP deve ser delimitado por caracteres especiais. Os delimitadores mais comuns são /, # e ~. A escolha do delimitador é importante para evitar a necessidade de escapar caracteres dentro do padrão.
// Delimitadores comuns
$padrao1 = '/[a-z]+/';
$padrao2 = '#[a-z]+#';
$padrao3 = '~[a-z]+~';
Os metacaracteres fundamentais incluem:
- . — qualquer caractere (exceto nova linha)
- ^ — início da string
- $ — fim da string
- * — zero ou mais ocorrências
- + — uma ou mais ocorrências
- ? — zero ou uma ocorrência
- [] — classe de caracteres
- () — grupo de captura
- | — alternância (OU)
- \ — escape
Classes predefinidas simplificam padrões comuns:
- \d — dígito (0-9)
- \w — caractere alfanumérico + underscore
- \s — espaço em branco
- \D, \W, \S — negações das classes acima
Modificadores alteram o comportamento do padrão:
- i — case-insensitive
- m — multiline (^ e $ passam a considerar quebras de linha)
- s — dotall (ponto passa a capturar nova linha)
- u — unicode (necessário para caracteres acentuados)
$texto = "Olá Mundo\nolá mundo";
preg_match('/^olá/im', $texto, $matches); // Encontra ambas as ocorrências
Busca e Verificação com preg_match e preg_match_all
preg_match() retorna 1 se o padrão for encontrado, 0 caso contrário, e false em caso de erro. O terceiro parâmetro opcional recebe as correspondências.
// Validação de e-mail simples
$email = "usuario@exemplo.com";
$padrao = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
if (preg_match($padrao, $email)) {
echo "E-mail válido";
}
preg_match_all() captura todas as ocorrências do padrão em uma string.
// Extrair todas as URLs de um texto
$texto = "Visite https://exemplo.com e http://teste.org";
$padrao = '/https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/';
preg_match_all($padrao, $texto, $urls);
print_r($urls[0]); // Array com as URLs encontradas
Para validação de CPF (apenas formato, não dígitos verificadores):
$cpf = "123.456.789-00";
$padrao = '/^\d{3}\.\d{3}\.\d{3}-\d{2}$/';
if (preg_match($padrao, $cpf)) {
echo "Formato de CPF válido";
}
Substituição e Manipulação com preg_replace e preg_replace_callback
preg_replace() substitui padrões por strings fixas. Aceita referências retroativas como \1 ou $1 para usar grupos capturados.
// Mascarar parte do e-mail
$email = "joao.silva@exemplo.com";
$padrao = '/(\w+)@/';
$substituicao = '$1***@';
echo preg_replace($padrao, $substituicao, $email);
// Resultado: joao.silva***@exemplo.com
preg_replace_callback() permite substituições mais complexas usando funções anônimas.
// Converter Markdown simples para HTML
$markdown = "**negrito** e *itálico*";
$html = preg_replace_callback(
'/\*\*(.+?)\*\*|\*(.+?)\*/',
function($matches) {
if (!empty($matches[1])) {
return "<strong>{$matches[1]}</strong>";
}
return "<em>{$matches[2]}</em>";
},
$markdown
);
echo $html; // <strong>negrito</strong> e <em>itálico</em>
O parâmetro $limit controla o número máximo de substituições:
$texto = "um dois três quatro";
echo preg_replace('/\s+/', ', ', $texto, 2); // um, dois, três quatro
Divisão e Filtragem com preg_split e preg_grep
preg_split() é uma alternativa avançada ao explode(), permitindo padrões complexos para delimitar a divisão.
// Dividir texto em palavras, ignorando pontuação
$texto = "Olá, mundo! Como vai?";
$palavras = preg_split('/[^\wáéíóúàèìòùâêîôûãõç]+/u', $texto, -1, PREG_SPLIT_NO_EMPTY);
print_r($palavras); // Array com as palavras limpas
Flags úteis incluem:
- PREG_SPLIT_NO_EMPTY — remove elementos vazios
- PREG_SPLIT_DELIM_CAPTURE — captura os delimitadores
- PREG_SPLIT_OFFSET_CAPTURE — retorna também a posição de cada elemento
preg_grep() filtra arrays, retornando apenas elementos que correspondem ao padrão.
// Extrair linhas de log com erro
$logs = [
"2024-01-01 INFO: Conexão estabelecida",
"2024-01-01 ERROR: Falha na autenticação",
"2024-01-01 WARNING: Disco quase cheio",
"2024-01-01 ERROR: Timeout"
];
$erros = preg_grep('/ERROR/', $logs);
print_r($erros); // Array com as linhas de erro
Boas Práticas e Otimização de Performance
preg_quote() escapa caracteres especiais automaticamente, essencial quando o padrão inclui dados dinâmicos.
$termo_busca = "preço (R$)";
$padrao = '/' . preg_quote($termo_busca, '/') . '/';
Evite backtracking catastrófico usando âncoras e quantificadores possessivos. Prefira (?>...) para grupos atômicos quando possível.
// Padrão potencialmente catastrófico
$ruim = '/(a+)+b/'; // Pode travar em strings longas sem 'b'
// Padrão otimizado
$bom = '/a++b/'; // Quantificador possessivo
Use grupos não-capturadores (?:...) quando não precisar do conteúdo capturado, economizando memória.
// Captura desnecessária
$ruim = '/(https?):\/\/([a-z]+)/';
// Otimizado
$bom = '/(?:https?):\/\/([a-z]+)/';
Sempre verifique erros com preg_last_error():
$resultado = preg_match($padrao, $texto);
if ($resultado === false) {
$erro = preg_last_error();
echo "Erro na expressão regular: $erro";
}
Exemplos Práticos e Casos de Uso Comuns
Validação de telefone brasileiro:
$telefone = "(11) 98765-4321";
$padrao = '/^\(\d{2}\)\s\d{4,5}-\d{4}$/';
if (preg_match($padrao, $telefone)) {
echo "Telefone válido";
}
Extração de tags HTML:
$html = "<a href='https://site.com'>Link</a> <img src='foto.jpg'>";
preg_match_all('/<a\s+href=[\'"]([^\'"]+)[\'"]>([^<]+)<\/a>/', $html, $links);
print_r($links[1]); // URLs dos links
Sanitização de entrada (remover caracteres não numéricos):
$entrada = "CPF: 123.456.789-00";
$apenas_numeros = preg_replace('/\D/', '', $entrada);
echo $apenas_numeros; // 12345678900
Conversão de data:
$data = "2024-01-15";
$padrao = '/(\d{4})-(\d{2})-(\d{2})/';
echo preg_replace($padrao, '$3/$2/$1', $data); // 15/01/2024
Expressões regulares com preg são ferramentas indispensáveis no PHP moderno. Dominar seu uso permite escrever código mais limpo, eficiente e seguro para manipulação de texto.
Referências
- PHP: PCRE — Documentação Oficial — Documentação completa das funções preg_* e sintaxe PCRE no PHP
- PHP: preg_match — Manual — Referência detalhada da função preg_match com exemplos
- Regular-Expressions.info: PHP PCRE Functions — Tutorial abrangente sobre expressões regulares PCRE no PHP
- PHP: preg_replace_callback — Manual — Documentação oficial com exemplos de substituições avançadas
- Regex101: PHP PCRE Tester — Ferramenta interativa para testar e depurar expressões regulares PCRE online
- PHP The Right Way: Regular Expressions — Guia de boas práticas para uso de regex em PHP