|
|
Paulo Silveira
Como utilizar o pacote java.util.regex do J2SE 1.4 e facilitar suas manipulações de Strings.
Introdução
Para este tutorial, é necessário que você já esteja familiarizado com expressões regulares, como as utilizadas em Perl ou PHP.
Utilizar Strings em java sempre foi muito fácil, por causa do sobrecarregamento do operador de adição.
Porém, fazer buscas e substituições era o contrário. A api da java.lang.String e java.lang.StringBuffer não eram o suficiente para tarefas um pouco mais complicadas, o que forçava os usuários a buscarem alternativas opensource, como o projeto oro da Apache Jakarta.
Após o lançamento da versão final do J2SE 1.4, as coisas melhoraram, e muito. Agora o J2SE conta com o pacote java.util.regex, que implementa expressões regulares.
Além deste pacote, as classes java.lang.String e java.lang.StringBuffer agora tem uma API que trabalha em conjunto com este novo pacote, e elas implementam a nova interface java.lang.String e java.lang.CharSequence, o que acabou com os pesadelos dos programadore quando tinham de criar um método sobrecarregado para aceitar tanto uma String quanto um StringBuffer.
Através deste tutorial, você irá aprender o básico de como utilizar estas novas classes e métodos.
Utilizando o pacote java.util.regex
É incrível, mas este pacote possui apenas 2 classes.
A classe Pattern representa uma expressão regular já compilada, isto é, já preparada para o uso.
Como "compilar" uma expressão regular é algo relativamente custoso, você não tem acesso direto ao construtor da classe, desta maneira, você é obrigado a utilizar o método estático compile(String regex), dando oportunidade para a classe criar um pool de expressões já compiladas, reaproveitando tempo no caso de você querer compilar a mesma expressão regular.
Criando um Pattern
1 Pattern pegaJava = Pattern.compile("java");
|
Com isto, temos uma expressão regular já engatilhada, que irá procurar pela String "java".
Agora, devemos utilizar o Pattern que já possuímos, para isso, precisamos de um Matcher, que irá "executar" a expressão em cima de uma dada String (CharSequence):
1 Pattern pegaJava = Pattern.compile("java");
2 // primeiro Java está em maíusculo!
3 Matcher m = pegaJava.matcher("O Java é muito java!");
4
5 // enquanto o Matcher encontrar o pattern na String fornecida:
6 while (m.find()) {
7 System.out.println(m.group());
8 }
|
Repare que desta maneira, o nosso Pattern apenas encontrou o "java" minúsculo. Você tem uma série de opções que pode utilizar quando cria um Pattern:
1 Pattern pegaJava = Pattern.compile("java", CASE_INSENSITIVE);
|
Ok, este exemplo foi muito simples, e apenas para ter a idéia básica do funcionamento da API.
Agora vamos a um exemplo real, suponho que temos um texto, e queremos encontrar todo o texto que está entre aspas simples.
Isto é: "E ele disse: 'java', 'guj', 'ninja'!" irá imprimir "java guj ninja". Vamos lá:
1 String frase = "E ele disse: 'java'!";
2 Pattern p = Pattern.compile("'(.*?)'");
3 Matcher m = p.matcher(frase);
4
5 while (m.find()) {
6 // chamada diferente:
7 System.out.println(m.group(1));
8 }
|
Agora nós utilizamos o método group(int) do Matcher ao invés do group(), porque? Desta maneira, será apenas retornado o conteúdo que foi encontrado referente ao primeiro parênteses do expressão regular, no nosso caso, o que está entre aspas simples. Caso houvessem mais grupos, a ordem é definida pela ordem de aparição dos parênteses de abertura. Um "grupo" nada mais é que o resultado da busca em relaçao a um dos parenteses. Se nenhum grupo for especificado, será considerada a expressão por inteira, como no caso anterior.
Utilizando expressões regulares pela API nova da String
Um exemplo clássico, é fazer o split de uma data do formato americano, passando-a para o formato brasileiro.
Antes, utilizaríamos um StringTokenizer, ainda correndo o risco de encontrar alguns NullPointerExceptions, mas agora:
1 String data = "12-30-2002"; // MM-DD-AAAA
2 /* usamos duas barras invertidas, pois caso
3 contrário ela será reconhecida apenas como caractere
4 de escape */
5 String dataBrasileira = data.replaceAll("(\\d\\d)-(\\d\\d)-(\\d\\d\\d\\d)", "\$2/\$1/\$3");
|
Fácil não? Acho que agora foi um pouco rápido. O Símbolo "$n", onde n é um número, indica que esta parte deve ser substituida pelo respectivo grupo! Perl tem a mesma funcionalidade.
Além disso, vamos dividir esse código para utilizar o pacote java.util.regex, para ficar claro o que acontece utilizando o replaceAll(String, String):
1 String data = "12-30-2002"; // MM-DD-AAAA
2 Pattern p = Pattern.compile("(\\d\\d)-(\\d\\d)-(\\d\\d\\d\\d)");
3 Matcher m = p.matcher(data)
4 if (!m.find()) {
5 throw new Exception("A data não está no formato americano");
6 }
7 String dataBrasileira = m.replaceAll("\$2/\$1/\$3");
|
Repare que no trecho anterior adicionamos um if para saber se o formato estava ok. Isto não iria acontecer se você utilizasse diretamente o método da String.
Agora suponha que você queira remover todos os tags HTML de uma String. Com o StringTokenizer você ia ter um bom trabalho, mas com a nova API:
1 String comHtml = "retirando <a href=zzz>código html</a>";
2 String semHtml = comHtml.replaceAll("<.*?>", "");
|
A Pattern "<.*?>" que dizer o seguinte: encontre tudo (o "." indica qualquer caracter exceto nova linha) que estiver entre < e >; o ? indica que o Pattern deve ser não guloso (greedy), isto é, ele deve parar o mais cedo possível, senão o .* iria reconhecer a String inteira (tente sem o ?).
Novamente, repare que o código anterior é 100% equivalente com este:
1 String comHtml = "retirando <a href=zzz>código html</a>";
2 Pattern p = Pattern.compile("<.*?>");
3 Matcher m = p.matcher(comHtml);
4 String semHtml = m.replaceAll("");
|
Com isto, você não vai mais sentir saudades do seu velho amigo StringTokenizer... Existem ainda outros métodos como o split(String) que faz a explosão da tring em um array, de acordo com a expressão regular passada para o método.
Este tutorial abrange apenas o começo, para maior referência, consulte a api da classe java.util.regex.Pattern, que uma boa explicação sobre os quantificadores que você pode usar na expressão regular.
|
|
|