Grupos nomeados no preg_match: pare de contar índice de $matches

Regex com cinco parênteses, e a cada leitura alguém conta no dedo pra saber se a data caiu no $matches[2] ou no $matches[3]. Aí entra mais um grupo no meio da expressão e todo código que lia índice numérico passa a devolver campo trocado, sem erro nenhum pra avisar. A saída é nomear os grupos.

A sintaxe é (?<nome>)

Parseando uma linha de erro do nginx, no PHP 8.3:

$linha = '2026/08/31 04:12:07 [error] 2187#0: *45 open() failed';
$re = '#^(?<data>d{4}/d{2}/d{2}) (?<hora>d{2}:d{2}:d{2}) [(?<nivel>w+)] (?<pid>d+)#';

if (preg_match($re, $linha, $m)) {
    printf("%s %s | nivel %s | pid %dn", $m['data'], $m['hora'], $m['nivel'], $m['pid']);
}

O PCRE continua preenchendo os índices numéricos junto com os nomes, então $m[1] ainda existe e vale o mesmo que $m['data']. Dá pra migrar uma expressão antiga aos poucos, nomeando um grupo por vez, sem quebrar quem já lê por número. A forma (?P<nome>...) faz exatamente a mesma coisa, é herança do Python. Nome de grupo aceita letra, número e underline, e não pode começar com dígito.

A armadilha do grupo opcional

$re = '/utm_source=(?<origem>w+)(?:&utm_medium=(?<meio>w+))?/';
preg_match($re, 'utm_source=google', $m, PREG_UNMATCHED_AS_NULL);
var_dump($m['meio']); // NULL, e nao "Undefined array key"

Sem a flag PREG_UNMATCHED_AS_NULL, grupo que não casou no fim da expressão nem entra no array, e o seu $m['meio'] vira um Warning: Undefined array key no PHP 8. Pior: grupo opcional no meio da expressão vem como string vazia, que passa batido em isset(). Com a flag, todo grupo declarado aparece no array, valendo null quando não casou.

Regra que adotei aqui: passou de dois grupos, nomeia. Quem for mexer na regex daqui a seis meses lê sozinho.

Dúvidas? Faça um comentário logo abaixo ou envie uma mensagem clicando aqui.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *