Arquivo

Arquivo de março, 2009

Expressões Regulares (java.util.regex.Matcher e java.util.regex.Pattern)

24, março, 2009

Buenas pessoal, nesse post estarei falando sobre Expressão Regular (ou regex, do inglês Regular Expression).

Aviso: “Este post não vai te transformar de iniciante em regex a um guru de regex” (frase adaptada do livro Certificação Sun para Programador Java 5, Guia de Estudo – Kathy Sierra e Bert Bates).

O regex é uma maneira de procurar um determinado padrão em um determinado texto. (para melhor entendimento do conceito ou conhecer a história do regex: http://pt.wikipedia.org/wiki/Expressão_regular)

Exemplo de regex teórico:

Texto: Olá Vânio, como você é legal!
Padrão: letras a,b,c,d,e.
A busca seria feita e o retorno seria:
a na posição 27
c nas posições 12,19
e na posição 25.

Note que não foram retornadas as letras acentuadas. Isso aconteceu porque a busca realmente não foi feita por letras com acentuação.
Em Java…
Por default também são diferenciadas letras maiúsculas de minúsculas, mas isso pode ser alterado quando o padrão for compilado (mostrarei exemplo).
Nesse exemplo teórico a posição (índice) é mostrada assumindo que o primeiro caractere da palavra começa por 1, porem em Java a contagem começa por 0 (zero), a partir de agora esse post tratará os índices como no Java. Em Java a posição do “a” encontrado seria a 26.

Como está organizado o regex em Java

As classes responsáveis pelo regex em Java estão no pacote java.util.regex. As classes que possivelmente você vai se deparar são:
Pattern;
Matcher;
PatternSyntaxException.

Pattern: é a classe que vai representar o padrão a ser procurado. Ela não possui construtor, você vai precisar usar o método public static Pattern compile(String s) ou o seu método sobrecarregado public static Pattern compile(String s, int flag) para obter uma instancia de Pattern.

Matcher: é a classe que vai gerenciar toda a pesquisa (faz as buscas, retorna resultados e etc). Ela também não possui construtor e você terá que usar o método public Matcher matcher(String s) da classe Pattern para obter a intancia de Matcher.

PatternSysntaxException: é a exception lançada ao compilar um pattern inválido.

Buscas Simples

Exemplos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Exemplo1 {
 
	public static void main(String[] args) {
 
		// O padrão será "es"
		Pattern pattern = Pattern.compile("es");
		// O texto será "busca simples"
		Matcher matcher = pattern.matcher("busca simples");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
 
	 }
 
}

A saída será:
11 – es

O método find() da classe Matcher, verifica se há ocorrência do padrão no texto, se há, ele assume que tal parte do texto foi utilizada, e no próximo find() que for executado, ele começará a procura a partir do primeiro índice depois do ultimo índice do padrão encontrado no texto (exceto quando usa-se quantificadores relutantes, mas já sai do escopo desse post).
O método start() da classe Matcher retorna o índice inicial do padrão encontrado no texto. Existe também o método end(), que ao contrario do start(), retorna o índice final.
O método group() da classe Matcher retorna a String encontrada com o padrão.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Exemplo2 {
 
	public static void main(String[] args) {
 
		Pattern pattern = Pattern.compile("ese");
		Matcher matcher = pattern.matcher("ese esese das");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
 
	}
 
}

A saída será:
0 – ese
4 – ese

Representação de onde o Matcher vai começar a procura após o find()

O ponto vermelho indica onde o Matcher vai começar a pesquisa depois das execuções do find()

Esses são exemplos de Buscas Simples, onde o padrão é uma String pura, mas e se nós precisássemos buscar qualquer letra?

Busca com metacaracteres

Os metacaracteres são caracteres especiais que são usados no padrão para que nossa busca se torne mais poderosa! (UAU!)
A seguir uma lista com alguns metacaracteres importantes:

  • \d – representa números.
  • \s – representa um espaço em branco.
  • \w – representa letras, números ou o “_” (underscore).
  • . – representa qualquer digito.
  • [] – representa uma cadeia de valores. Ex: [a-c] buscaria a ou b ou c.
  • ? – representa zero ou uma ocorrência.
  • * – representa zero ou mais ocorrências.
  • + – representa uma ou mais ocorrências.
  • ^ – representa negação.
  • () – agrupa os padrões, usado com os metacaracteres acima. Ex: (.)* retornaria o texto inteiro.

Para poder usar os metacaracteres \d, \s, \w você precisa adicionar uma barra invertida (\) na frente do metacaracter caso contrario o compilador vai interpretar isso como um caractere de escape.
Exemplo de metacaracter com escape: \\d

Com os metacaracteres nossos padrões começam a ficar interessantes, digamos que você precisa encontrar os telefones em uma lista onde estão disponíveis telefones no formato 0000-0000, como seria nosso padrão?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class BuscarTelefone {
 
	public static void main(String[] args) {
 
		// Nosso padrão.
		String padrao = "\\d\\d\\d\\d-\\d\\d\\d\\d";
		// Nosso texto simulando uma lista cheia de telefones. (o \n é para
		// simular várias linhas)
		String lista = "12341234\n1324-1234\n9900-0000\n1234567\nXC484714";
		Pattern pattern = Pattern.compile(padrao);
		Matcher matcher = pattern.matcher(lista);
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
 
	}
 
}

A saída seria:
9 – 1324-1234
19 – 9900-0000

É um padrão básico que vai procurar quatro números (\d), um “-” e mais quatro números.
Interessante, não? Ainda não! Vamos pensar que nós temos também na lista telefones no formato 00000000, ou seja, queremos os telefones nos formatos: 00000000 e 0000-0000, o que precisamos alterar no código? Vamos usar o metacaracter ? (zero ou um).
Alterando o código para:

11
String padrao = "\\d\\d\\d\\d(-)?\\d\\d\\d\\d";

A saída agora fica:
0 – 12341234
9 – 1324-1234
19 – 9900-0000

A grande sacada foi o uso do quantificador “?”.

Legal, mas foi usado ( e ) mas isso não foi incluso no padrão, caso eu quisesse procurar por (, como faria?
Precisariamos escapar o que fossemos procurar, exemplos:
Caracter “(“, ficaria: “\\(” (usamos duas barras pois uma barra o Java entende como caractere de escape comum (\n,\t e etc) e com a outra barra estamos escapando a barra para que ela seja usada).
Caracter “.”, ficaria “\\.”.

Alguns outros exemplos:

O “[]“

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Exemplo3 {
	public static void main(String[] args) {
		// Esse padrão busca de a até z e A até Z.
		Matcher matcher = Pattern.compile("[a-zA-Z]").matcher(
			"A b C d x 5 7 1 - x _");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
	}
}

A saída:
0 – A
2 – b
4 – C
6 – d
8 – x
18 – x

O “+”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Exemplo4 {
	public static void main(String[] args) {
		// Se não fosse usado o metacaracter + o padrão não buscaria números com mais de 2 dígitos.
		Matcher matcher = Pattern.compile("\\d+").matcher(
			"A b C d x 5 7 1 - x _ 156 1 5 48");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
	}
}

A saída:
10 – 5
12 – 7
14 – 1
22 – 156
26 – 1
28 – 5
30 – 48

O “^”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Exemplo5 {
	public static void main(String[] args) {
		// Note o uso do && para juntar dois conjuntos
		// Esse padrão busca de a até z, menos o x.
		Matcher matcher = Pattern.compile("[a-z&&[^x]]").matcher(
			"A b C d x 5 7 1 - x _");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
	}
}

A saída:
2 – b
6 – d

Como prometi no começo do post, um exemplo de como retirar o Case Sensitive (diferenciar letra maiúscula de minúscula). Note que esse exemplo fica igual o exemplo 3.

1
2
3
4
5
6
7
8
9
10
11
12
13
package br.com.vaniomeurer.blog.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Exemplo6 {
	public static void main(String[] args) {
		// Esse padrão busca de a até z e A até Z.
		Matcher matcher = Pattern.compile("[a-z]", Pattern.CASE_INSENSITIVE).matcher(
			"A b C d x 5 7 1 - x _");
		while (matcher.find()) {
			System.out.println(matcher.start() + " - " + matcher.group());
		}
	}
}

A saída:
0 – A
2 – b
4 – C
6 – d
8 – x
18 – x

Por hoje é isso, espero que esse post possa ajudar alguém no mundo das regex.

Vânio Meurer (vaninhO).

Java SE , , , ,

Certificação SCJP. Passei!

20, março, 2009

Com muita felicidade venho escrever esse post.
Depois de alguns meses de estudos, fui fazer minha prova de certificação, fiz 79% e consegui a tão esperada certificação.
Bom, vou contar como tudo rolou.

Estudos, o começo
Comecei a estudar pelo livro “Certificação Sun para Programador Java 5. Guia de Estudo – Kathy Sierra e Bert Bates” em outubro de 2008. Estudava algumas horas por dia, lia o quanto dava vontade, caso estivesse inspirado lia bastante, caso não, lia pouco ou nada.

Comprando o voucher
Em novembro comprei meu voucher aproveitando uma promoção de retake. Retake é uma promoção que a Sun faz para suas certificações, ela te da a chance de tentar uma segunda vez caso não passe na primeira tentativa, mas caso passe, você não tem direito a mais nada.

Tentando marcar a prova
Em janeiro eu já tinha terminado de ler o livro e me sentia preparado a fazer o exame, fui tentar marcar a prova mas diversos problemas surgiram para me impedir (desde transporte até não ter provas disponíveis em fevereiro).

Mock Exam
Como já havia terminado a leitura eu de vez em quando tentava responder algumas perguntas de qualquer mock online.
Alguns mocks que respondi foram:
CaelumMock
Inquisition Mock Exam
O Caelum eu devo ter respondido por completo umas duas vezes, com 20 questões por exame.
O Inquisition eu fiz algumas vezes com um numero de 20 questões, o Inquisition tem um banco de perguntas bem legal, é inglês.

Marcando a prova
No dia 16 de março meu fiel escudeiro (haha) Leo Vitor resolveu marcar sua consulta médica em Florianópolis pro dia 19, foi ai que surgiu minha oportunidade de ir fazer a prova, e foi nessa data que marquei a prova.
Marquei no Senac Tecnologia em Floripa, a prova foi a SCJP 1.5 (310-055) por ser em português.

A prova
Minha prova estava marcada pro horário das 15:15, cheguei na prova 14:40, logo que cheguei já assinei o que precisava e fui fazer a prova, não tinha ninguém fazendo provas, por isso já me adiantaram.
Levei uma água como o livro me sugeriu, mas não pude entrar com ela, a instrutora me informou que poderia lhe chamar para beber caso necessário.
O local da prova era um tanto engraçado, um quartinho de 1,5m por 1,5m mais ou menos, com uma câmera filmando, um PC, um ar condicionado do qual eu tive a posse do controle, uma espécie de folha plastificada, um pincel atômico para escrever na folha e um apagador.
Antes de começar as perguntas da prova você precisa responder umas perguntas relativas ao teu conhecimento (é informado que não influência nas questões da prova, coisa que duvido muito).
Existem três tipos de perguntas na prova, as perguntas que aparece o texto na tela normal, as perguntas de “arrastar e soltar” (drag and drop) que você precisa clicar num botão que se não me engano chamava-se Tabela e a outra aparecia a pergunta na tela e pedia que você clicasse em Exibir para que fosse aberto um popup com mais código.
Todas as respostas (tirando as drag and drop) eram objetivas, algumas múltipla escolha outras uma única escolha. Detalhe importante é que diferente dos mocks exam, na prova as perguntas de múltipla escolha te informam quantas são as respostas que você precisa selecionar (isso ajuda horrores).

Fim de prova
Terminei a prova sobrando 55minutos, meu resultado foi 79%. Para mim foi um resultado satisfatório, pois fiz a prova muito tempo depois de ter terminado de ler o livro.
Meu resultado detalhado foi:
Declarações, Inicialização e Escopo: 100%
Controle de Fluxo: 72%
Conteúdo da API: 80%
Concorrência: 62%
Conceitos OO: 80%
Coleções / Genéricos: 70%
Fundamentos: 81%

Bom é isso, agora o blog ganhou um selinho. :D
Vânio Meurer (vaninhO).

Java SE , , , , ,