segunda-feira, 9 de janeiro de 2012

Expressões Regulares I

Uma das coisas mais difíceis para o pessoal que desenvolve em Windows é apresentar a utilizar as expressões regulares ou regex. O pessoal do linux que já trabalham com administração mais avançada nos terminais vão encontrar estas expressões até mesmo nas linhas de comando. Parece um bicho de 8 cabeças (e não vou mentir, início é mesmo e depois a gente ainda se enrola nas expressões mais complicadas), mas o uso vai fixando esta idéia na cabeça da gente.

Para utilizar estas expressões você vai achar um pacote no Java denominado java.util.regex. Sugiro dar uma olhada na documentação no site da Oracle para mais detalhes. Este pacote oferece:
  • uma Interface:
    •  MatchResult
  • duas Classes:
    • Matcher
    • Pattern
  • uma Exceção:
    • PatternSyntaxException
A classe Pattern é uma representação compilada pelo Java da expressão. Esta classe não possui construtores, portanto para criar um padrão compilado devemos chamar inicialmente Pattern.compile que retorna um objeto do tipo Pattern. Este método aceita a expressão regex como argumento principal.

A classe Matcher é o interpretador do padrão e busca os resultados da operação sobre a string. Esta classe também não tem construtor público, e um objeto é criado chamando pattern.matcher.

PatternSyntaxException é uma exceção (não verificada) que indica que há um erro na sintaxe da regex.

Vamos ver um exemplo para testar os padrões. A classe abaixo é uma modificação da classe RegexTestHarness da Oracle que permite que entremos com uma expressão regular e uma string e a classe executa a expressão regular sobre a string apresentando o resultado da pesquisa. Acho ela muito prática para aprender qual o comportamento do matcher para um determinado padrão, pois nos permite simular diversos padrões.

import java.io.Console;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class TestaExpressoesRegex {

  public static void main(String[] args){
    // usamos esta classe para ler a entrada de dados a partir da console
    // (prompt de comando do windows ou terminal no linux)
    Console console = System.console();
    if (console == null) {
      System.out.println("Não foi localizada a console (prompt)!");
      System.exit(1); // sai com erro
    }
    // loop sem fim
    while (true) {
      // cria a classe que manipula o padrão - string com a pesquisa regex
      Pattern pattern = Pattern.compile(console.readLine("Entre com a expressao regex      : "));
      //o texto digitado na console é enviado para o método Pattern.matcher
      // que processa a string frente ao padrão regex
      // o resultado é Matcher
      Matcher matcher = pattern.matcher(console.readLine("Entre com o texto a ser pesquisado : "));
      // loop para apresentar o resultado --> podem existir diversos resultados
      // em função da repetição do padrão
      boolean achou = false;
      while (matcher.find()) { // enquanto achou padrao
        console.format("Encontrado o texto [%s] na posição de %d a %d.%n",
          matcher.group(), // texto encontrado
          matcher.start(), // posição inicial
          matcher.end());  // posição final
        achou = true;
      }
      if(!achou ){
        console.format("Não foram encontradas mais entradas.%n");
      }
    }
  }
}

Para entendermos melhor o funcionamento desta classe, vamos executar alguns testes com ela e analisar os resultados.



A procura funciona mesmo tendo acrescentado o ponto no final da expressão regex, isto acontece por que este ponto é considerado um metacaracter. Veja que os resultados (grupos) encontrados foram roe, rou e rom.

Os metacaracteres são caracteres especiais que são interpretados pelo matcher de forma diferente. Neste exemplo o "." quer dizer qualquer caracter. É por isto que o segundo exemplo funciona também.

Existem diversos metacaracteres suportados por java.util.regex, eles são:
<([{\^-=$!|]})?*+.>

E se queremos procurar por uma string que tenha ponto (ou qualquer outro metacaracter)?

Existem duas maneiras de informar ao interpretador regex que o metacaracter deve ser tratado como um caracter ordinário:
  1. colocar uma barra invertida antes do metacaracter (por exemplo \.)
  2. colocar os metacaracteres entre \Q e \E (por exemplo
\Q<([{\^-=$!|]})?*+.>\E 
permite procurar a lista de todos os metacaracteres).
Continua na parte I >>>

Nenhum comentário:

Postar um comentário