Java: Expressões Regulares (regex) em Java


Também conhecidas como regex (regular expressions), expressões regulares são sentenças com códigos que podem representar uma string, de forma genérica.
Por exemplo, o CEP é da forma: ddddd-ddd
Onde 'd' é um dígito qualquer, entre 0 e 9. Essa expressão representa toda a gama de CEP's em nosso país.

São usadas também para a criação de compiladores, através de expressões regulares bem complexas, que podem representar qualquer trecho de código, e acusar erro de sintaxe, caso o código escrito não case com as expressões regulares.

Em nossos aplicativos, usaremos expressões regulares para garantir que a entrada de dados esteja sob uma forma específica.
Por exemplo, caso necessitemos que o usuário digite um CEP e ele escrever:
dddd*-ddd

O que ele digitou não vai casar com a expressão regular que usamos para validar o CEP, pois o número de CEP não aceita asterisco.
As expressões regulares são uma ferramenta bem antiga, usada desde a época do Unix, e é usada nas mais diversas linguagens de programação, como em Perl, e em programas, como o sed.

Vamos a alguns exemplos:
\d -> representa qualquer dígitos
\D -> representa tudo, menos dígito

\w -> representa qualquer caractere de palavra
\W -> representa tudo que não seja um caractere de palavra

\s -> representa qualquer espaço em branco(" ", tab)
\S -> representa tudo que não seja espaço em branco

[a-z] -> representa qualquer letra minúscula do alfabeto
[A-Z] -> representa qualquer letra maiúscula do alfabeto
[a-zA-Z] -> representa qualquer letra do alfabeto, seja maiúscula ou minúscula
| -> representa o 'ou'. "a|b" casa com 'a' ou com 'b', ou com os dois

Vejamos alguns quantificadores
. -> substitui qualquer caractere
* -> o caractere anterior aparece nenhuma ou mais vezes
+ -> o caractere anterior aparece uma ou mais vezes
{a} -> o caractere anterior se repete 'a' vezes
{a,} -> o caractere anterior se repete pelo menos 'a' vezes
{a,b} -> o caractere anterior se repete entre 'a' e 'b' vezes


A representação de dígito é '\d', mas dentro de strings, para '\' valer, temos que escapá-la.
Logo, podemos representar um CEP como: "\\d\\d\\d\\d\\d-\\d\\d\\d"
Ou "\\d{5}-\\d{3}"
O método ficaria:

meu_cep.matches("\\d{5}-\\d{3}") -> retorna 'true' se o CEP for digitado correto, e 'false' caso errado

Para validar um nome, sabemos que o primeiro caractere é maiúsculo:
nome.matches("[A-Z][a-zA-Z]*") -> retorna 'true' se a primeira letra do nome for maiúscula, e 'false' caso errado

O Java provém alguns métodos para o uso de regex e substituições:
std = std.replaceAll("a", "b") -> substitui todas as ocorrências de 'a' por 'b'

Também podemos usar expressões regulares no método 'replaceAll':
std = std.replaceAll("\\w+","a") -> substitui todas as palavras por 'a'
std = std.replaceFirst("\\d","a") -> substitui a primeira ocorrência de um dígito por 'a'
String[] pedacos = std.split("a") -> divide a string 'std' em partes, cujo separador é 'a' e armazena no vetor de strings 'pedacos'. Por exemplo, para separarmos as palavras de uma string, usamos "," ou ",\\s*" como separador

É importante frisar que, nos vários métodos e classes para o tratamento de regex, use a classe String.
Se usar a StringBuilder terá erros.


Caso queira prosseguir no mundo das regex e em Java, esse package possui duas classes que lhe serão bastante úteis:a Pattern, para usar uma expressão regulas e a Matcher, que também usa uma expressão regular mas também uma CharSequence, onde você irá procurar o padrão para casar.
Para expressões regulares que serão usadas somente uma vez, se recomenda usar o método static 'matches' da Pattern. Porém, se for usada mais de uma vez, se aconselha a usar o método static 'compile', que retorna um objeto do tipo Pattern, onde posteriormente se pode chamar o método 'matcher'.

A classe Matcher também provém o método 'matches' e faz a mesma coisa, porém não recebe argumentos. Ela age por encapsulamento no objeto do tipo Matcher.
Essa classe também possui outros métodos bastante úteis, como o 'replaceFirst', 'replaceAll', 'find' , 'lookingAt' etc, que, pelo nome, é possível saber o que cada um faz.


Tenha em mente que as possibilidades das expressões regulares são inúmeras e ilimitadas. Compiladores são feitos usando expressões regulares! Isso por si só já mostra o poder das regex.
Por isso, não entrarei tão afundo no assunto.
Tendo estudado esse artigo, você saberá as possibilidades das Expressões Regulares, e irá se lembrar delas caso um dia necessite delas.

Expressões Regulares são universais. Você pode aprender e usar em vários ramos e linguagens.
Eu mesmo já falei aqui em outros artigos, como no de sed. Lá está até mais completo, se eu falasse mais aqui, estaria simplesmente repetindo o que está escrito lá.
Portanto, dê um pulinho no artigo de Regex da parte de 'sed', é uma continuação daqui:

http://programacaoprogressiva.blogspot.com.br/2012/07/sed-parte-vi-expressoes-regulares.html

Regex é assunto pra livros! E é isso que vou indicar, um site de um brasileiro, o Aurelio Jargas, mestre em Expressões Regulares que publica e divulga GRATUITAMENTE seu material!

http://aurelio.net/regex/

Vale ressalvar que o java possui um pacote (package) voltado para expressões regulares.
Vale uma conferida na documentação:
java.util.regex

4 comentários:

Adriano disse...

Ótima explicação. Simples e direta!
Obrigado!

Telmo Leonel disse...

Olá pessoal da programação progressiva eu sou muitoooooo agradecido por tudo que vocês fizeram por mim eu não sabia nada sobre java mas graças a vocês até programas com GUI já estou fazendo.

Mas tou com uma dúvida terrível mas vocês são tão bons que com certeza vão poder me ajudar:

Como posso fazer para verificar de forma eficaz se uma string tenha letras, mesmo que ela apareça misturada com números? Obrigado por tudo.

Tunico disse...

Por favor Senhores.
Como encontro colchetes numa String através de expressões regulares.
Ex. [13]

Tunico disse...

Telmo acho que isso pode te ajudar
package br.com.xti.textmining;

public class Tester {

public static void main(String[] args) {
// TODO Auto-generated method stub
TextAnalysis ta = new TextAnalysis();
ta.readText();
ta.startAnalysis();
ta.displayAnalysis();
ta=null;
}

}

package br.com.xti.textmining;

import java.util.Scanner;

public class TextAnalysis {
private String text;
private int lettersCount=0;
private int digitsCount=0;
private int spaceCount=0;
private int otherCount=0;

public String getText(){
return text;
}

public int getLettersCount(){
return lettersCount;
}

public int getDigitsCount(){
return digitsCount;
}

public int getSpaceCount(){
return spaceCount;
}

public int getOtherCount(){
return otherCount;
}

public void readText(){
System.out.print("Entre com o texto abaixo: \n");
Scanner in = new Scanner(System.in);
text = in.nextLine();
in = null;
}

public void startAnalysis(){
lettersCount=0;
digitsCount=0;
spaceCount=0;
otherCount=0;
char c;

for(int i=0;i='A' && c<='Z')||(c>='a' && c<='z'))
lettersCount++;
else if(c>='0'&&c<='9')
digitsCount++;
else if(c=='\t' || c==' ' || c=='\n')
spaceCount++;
else
otherCount++;
}
}

public void displayAnalysis(){
System.out.printf("\nLetras........: %d", lettersCount);
System.out.printf("\nNúmeros.......: %d", digitsCount);
System.out.printf("\nEspaços.......: %d", spaceCount);
System.out.printf("\nOutros........: %d", otherCount);
}
}

Veja também: