PHP e Expressões Regulares: modo avançado. Episódio 1 Comment
Expressões regulares são o cinturão de utilidades do desenvolvimento. Presente na grande maioria das linguagens de programação, serve principalmente para identificar padrões em textos ou strings. Tempos idos, iniciei um projeto que exigira um pouco mais de poder na análise e busca de padrões de textos em Strings. Quem já trabalhou com ER sabe que mantê-las não é lá um divertido passatempo, manter as ER’s dos outros então, não desejo nem pro meu pior adversário em Real Football. Expressões Regulares bem organizadas não voltarão pra puxar seu pé numa futura manutenção ou implementação. Hoje apresentarei algumas funcionalidades muito úteis para organizar e melhorar o uso de ER’s. Estamos apenas começando!
Comentários dentro de ER’s
Era uma vez uma expressão que começou casando apenas números de 0 a 9, mas depois de alguns pedidos de olhos grandes e marejados do seu GP, ela se tornou indecifrável! Exemplifico.
# Encontra numeros de telefone com Operadora e DDD opcionais
preg_match('/((\()?0[0-9]{2,4}(\))?\s?)?\s?[0-9]{4}-[0-9]{4}/', $telefone, $mt );
Agora com uma abordagem distinta:
preg_match(
'/
( # inicia novo grupo
(\()? # pode ter de 0 a 1 "("
0[0-9]{2,4} # Zero seguido de um sequencia de 2 a 4 numeros
(\))? # pode ter de 0 a 1 ")"
\s? # busca por um ou nenhum espaco
)? # fim deste grupo, que pode ou nao estar no numero de telefone
\s?[0-9]{4} # aqui, queremos uma sequencia numerica de 4 numeros precedida ou nao de espaco
-?[0-9]{4} # outra sequencia numerica de 4 numeros, mas precedida ou nao de traco
/x',
$telefone
);
Claro e conciso. O grande responsável pelos comentários é esse “xizinho” depois do separador. Conhecido como parâmetro modificador, permite que espaços em branco sejam ignorados, a não ser que se use “\s” dentro da ER. Os comentários são postos com a tralha “#”.
Testando:
$telefone = array( '(01511) 5555-6789', '02119 76767676', '04111 8111345', '2111 81113456');
foreach( $telefone as $numero ){
if( preg_match( '/
( # inicia novo grupo
(\()? # pode ter de 0 a 1 "("
0[0-9]{2,4} # Zero seguido de uma sequencia de 2 a 4 numeros
(\))? # pode ter de 0 a 1 ")"
\s? # busca por um ou nenhum espaco
)? # fim deste grupo, que pode ou nao estar no numero de telefone
\s?[0-9]{4} # aqui, queremos uma sequencia numerica de 4 numeros precedida ou nao de espaco
-?[0-9]{4} # outra sequencia numerica de 4 numeros, mas precedida ou nao de traco
/x', $numero, $mt ) )
{
echo "Este numero de telefone $numero eh valido
";
}
else
{
echo "Este numero de telefone $numero nao eh valido
";
}
}
/* saida
Este numero de telefone (01511) 5555-6789 eh valido
Este numero de telefone 02119 76767676 eh valido
Este numero de telefone 04111 8111345 nao eh valido
Este numero de telefone 2111 81113456 eh valido
*/
Se eu encontrar expressões regulares mal organizadas a partir de agora, vou xingar muito no twitter.
Callbacks em ER’s
Em PHP existe uma função onde podemos aplicar callbacks( funções que trabalham por debaixo do pano, comendo pelas beiradas ) a cada vez que o padrão é encontrado numa String. Se trata de preg_replace_callback. Com esta ferramenta, podemos manipular tudo o que a expressão regular encontra através de uma função pré-definida que entra como um parâmetro em preg_replace_callback. Imagine as possibilidades. Umas delas é muita usada em foruns da internet, onde algumas palavras-chave são substituídas por emoticons, tags html ou dados. Exemplo:
# o template
$templateBemvindo = "[saudacao] [nome] [sobrenome]! Este eh o seu acesso de numero [quantidade_acessos].
Ah, voce tem [mensagens] mensagens."
# agora a nossa classe incumbida de cuidar dos dados e substituí-los
Class Dados{
# estes dados podem vir de um banco de dados, xml, etc...
public static $dados = array( 'nome' => 'Adriano', 'sobrenome' => 'Alves', 'quantidade_acessos' => 77, 'mensagens' => 16 );
# método responsável em procurar e substituir os dados encontrados
public function substituir( $matches ){
if( array_key_exists( $matches[1] , self::$dados ) ){
return self::$dados[ $matches[1] ];
}
else{
Zend_Debug::dump( $matches, 'Matches' );
}
}
}
$msg = preg_replace_callback( '/\[(.+?)\]/x', array( 'Dados', 'substituir' ), $bemvindoTemplate );
echo $msg;
Impressionante essa função. Repare que apesar do método “substitiuir” ser um método público de objeto (não estático) ainda assim foi usado. Teste usar a string ‘Dados::substituir’. Estou usando PHP 5.3.* e funcionou igual. A ER encontra tudo o que está entre ‘[' e ']‘ e guarda na variável $matches no índice 1. Esta variável $matches entra como primeiro argumento do método ’substituir’, que por sua vez busca por índices ( keys ) iguais no vetor estático $dados. preg_replace_callback retorna tudo bonito e reluzente.
Se você gostou deste episódio, não perca os próximos capítulos. Se não gostou, volte assim mesmo e confira o que vem por aí. Falarei de outras funções e técnicas para se trabalhar com ER’s. Dúvidas? Sugestões? Siga-me no twitter ou poste um comentário. Obrigado pela visita!