Introdução às Expressões Regulares em Java
Introdução às expressões regulares em Java com o pacote java.util.regex.
Uma expressão regular (regex) é um padrão compacto que descreve um conjunto de strings. Em Java, o pacote java.util.regex transforma esses padrões em um motor de correspondência pequeno e rápido que pode ser aplicado a qualquer texto — para validar entradas, buscar substrings, extrair campos ou reescrever conteúdo. Este capítulo apresenta as peças antes de você começar a escrever seus próprios padrões.
O que é uma Expressão Regular
Um regex é apenas uma string escrita em uma sintaxe especial, mas Java não a interpreta caractere por caractere a cada vez. Em vez disso, você compila o padrão uma vez em um objeto Pattern e depois o aplica à entrada por meio de um Matcher. A forma compilada é uma máquina de estados eficiente, portanto reutilizar um Pattern em muitas entradas é muito mais barato do que recompilar.
Os padrões descrevem estrutura: um literal como cat corresponde exatamente àquelas letras, enquanto metacaracteres descrevem formas — \d é qualquer dígito, + significa "um ou mais", . significa "qualquer caractere". Combine-os e você pode descrever números de telefone, e-mails ou linhas de log em uma única linha de código.
import java.util.regex.Pattern;
public class FirstPattern {
public static void main(String[] args) {
// Compile the pattern once; reuse the result.
Pattern digits = Pattern.compile("\\d+");
System.out.println(digits.matcher("abc123").find()); // true
System.out.println(digits.matcher("hello").find()); // false
}
}Observe a barra invertida dupla: \d no regex deve ser escrito \\d em um literal de string Java, porque o compilador Java consome uma barra invertida primeiro.
Pattern e Matcher
Duas classes fazem quase todo o trabalho. Pattern é o blueprint compilado, reutilizável e thread-safe. Matcher é o motor com estado que executa esse blueprint em uma entrada específica — ele rastreia onde você está no texto, quais grupos foram capturados e onde o último match terminou. Crie um novo Matcher por entrada; nunca compartilhe um entre threads.
| Tipo | Função |
|---|---|
Pattern | O padrão compilado. Imutável, thread-safe, reutilizável. |
Matcher | Aplica um Pattern a uma entrada. Mantém o estado do match. |
Pattern.compile(regex) | Constrói um Pattern a partir de uma string de regex. |
pattern.matcher(input) | Retorna um Matcher vinculado àquela entrada. |
String.matches(regex) | Auxiliar de uso único que compila e faz a correspondência completa em uma única chamada. |
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternAndMatcher {
public static void main(String[] args) {
Pattern p = Pattern.compile("\\w+@\\w+\\.\\w+");
Matcher m = p.matcher("ping me at [email protected] please");
if (m.find()) {
System.out.println("Found email: " + m.group());
}
}
}find() vs matches()
O erro mais comum entre iniciantes é confundir as duas formas de executar um padrão. matches() exige que a entrada inteira corresponda ao padrão do início ao fim. find() varre em busca de qualquer substring que corresponda, e pode ser chamado repetidamente para percorrer cada ocorrência. lookingAt() fica entre os dois: ancora no início, mas não exige correspondência até o fim.
| Método | Ancorado no início? | Deve corresponder até o fim? | Repetível? |
|---|---|---|---|
matches() | sim | sim | não |
lookingAt() | sim | não | não |
find() | não | não | sim |
import java.util.regex.Pattern;
public class FindVsMatches {
public static void main(String[] args) {
Pattern p = Pattern.compile("\\d+");
System.out.println(p.matcher("42").matches()); // true (whole input)
System.out.println(p.matcher("age 42").matches()); // false (extra text)
System.out.println(p.matcher("age 42").find()); // true (substring)
System.out.println(p.matcher("age 42").lookingAt()); // false (no digit at start)
}
}Sintaxe Comum com a Qual Você Vai Trabalhar
A maioria dos padrões reais é montada a partir de um pequeno vocabulário de blocos de construção: classes de caracteres, atalhos predefinidos, quantificadores e âncoras. Aprender esses elementos cobre grande parte do caminho. Cada construção tem um capítulo dedicado — veja Sintaxe de Regex, classes de caracteres e quantificadores para os detalhes completos.
| Construção | Significado | Exemplo |
|---|---|---|
. | Qualquer caractere único (exceto nova linha) | a.c corresponde a abc, axc |
\d \w \s | Dígito, caractere de palavra, espaço em branco | \d\d corresponde a 42 |
[abc] | Qualquer um de a, b, c | [aeiou] corresponde a uma vogal |
[^abc] | Qualquer caractere exceto a, b, c | [^0-9] corresponde a um não-dígito |
* + ? | Zero+, um+, zero-ou-um | ab+ corresponde a ab, abb |
{n} {n,m} | Exatamente n, entre n e m | \d{3} corresponde a 555 |
^ $ | Início, fim da entrada/linha | ^Hi corresponde a um Hi no início |
(...) | Grupo de captura | (\d{4}) captura quatro dígitos |
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GroupsExample {
public static void main(String[] args) {
// Two capturing groups: year and month.
Pattern date = Pattern.compile("(\\d{4})-(\\d{2})");
Matcher m = date.matcher("Released 2025-11 to users");
if (m.find()) {
System.out.println("Full: " + m.group(0)); // 2025-11
System.out.println("Year: " + m.group(1)); // 2025
System.out.println("Month: " + m.group(2)); // 11
}
}
}Exemplo Trabalhado
O programa abaixo compila um padrão de número de telefone e exercita toda a API sobre ele: percorre cada match com find(), lê grupos de captura e posições de match, contrasta find() com matches(), e reescreve o texto com replaceAll(). Execute-o para ver o motor em ação.
O que observar na execução:
find()é chamado em um loop e retorna dois matches, portanto o mesmoMatcherpercorre o texto uma ocorrência por vez até retornarfalse.group(1)egroup(2)retornam as sub-partes entre parênteses (555e1234), enquantogroup()sem argumento retorna o match completo.start()eend()informam os deslocamentos de caractere de cada match, que é como você destacaria ou recortaria o texto original.matches()sobre a sentença completa imprimefalseporque o padrão não cobre a string inteira, enquanto"555-1234"sozinho imprimetrue— prova de quematches()é somente para entrada completa.replaceAll("XXX-XXXX")reescreve cada match em uma única passagem, produzindo a sentença mascarada e mostrando como os padrões conduzem a transformação de texto.
Próximos Passos
Agora que você conhece as peças em movimento — Pattern, Matcher e a diferença entre find() e matches() — aprofunde-se com os capítulos temáticos:
- Pattern and Matcher — a API completa para compilar e executar padrões.
- Sintaxe de Regex — cada metacaractere e escape, explicado.
- Classes de caracteres — conjuntos, intervalos e negação.
- Quantificadores — repetição gananciosa, relutante e possessiva.
- Grupos de captura — extração e backreference de sub-partes.
- Flags — case-insensitive, multiline e outros modificadores.