Expresiones Regulares en Java: Dominando la Coincidencia de Patrones con java.util.regex
Java proporciona el paquete java.util.regex para la coincidencia de patrones mediante expresiones regulares. Las expresiones regulares de Java son muy similares al lenguaje de programación Perl y resultan muy fáciles de aprender.
Conceptos Fundamentales
Una expresión regular es una secuencia especial de caracteres que ayuda a buscar, encontrar o manipular cadenas de texto utilizando una sintaxis especializada contenida en un patrón. Permiten buscar, editar o manipular texto y datos de forma potente y flexible.
Clases Principales del Paquete java.util.regex
El paquete consta principalmente de tres clases:
- Pattern (Patrón): Representa una expresión regular compilada. No tiene constructores públicos; se crea invocando el método estático
compile(), que acepta la expresión regular como primer argumento. - Matcher (Coincidente): Es el motor que interpreta el patrón y realiza operaciones de coincidencia sobre una cadena de entrada. Se obtiene invocando el método
matcher()sobre un objetoPattern. - PatternSyntaxException: Excepción no verificada que indica un error de sintaxis en el patrón de expresión regular.
Grupos de Captura
Los grupos de captura permiten tratar varios caracteres como una sola unidad. Se crean colocando los caracteres entre paréntesis. Por ejemplo, la expresión regular (dog) crea un grupo único con las letras "d", "o" y "g".
Los grupos se numeran contando los paréntesis de apertura de izquierda a derecha. En la expresión ((A)(B(C))) hay cuatro grupos:
((A)(B(C)))(grupo 1)(A)(grupo 2)(B(C))(grupo 3)(C)(grupo 4)
Para conocer el número de grupos, se llama al método groupCount() en un objeto Matcher. Existe además un grupo especial, el grupo 0, que siempre representa la expresión completa y no se incluye en el recuento de groupCount().
Ejemplo: Extraer dígitos de una cadena alfanumérica
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main(String args[]) {
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(line);
if (m.find()) {
System.out.println("Valor encontrado (grupo 0): " + m.group(0));
System.out.println("Valor encontrado (grupo 1): " + m.group(1));
System.out.println("Valor encontrado (grupo 2): " + m.group(2));
} else {
System.out.println("NO MATCH");
}
}
}
Salida:
Valor encontrado (grupo 0): This order was placed for QT3000! OK? Valor encontrado (grupo 1): This order was placed for QT300 Valor encontrado (grupo 2): 0
Sintaxis de Expresiones Regulares en Java
A continuación se muestra una tabla con los metacaracteres y su significado:
| Subexpresión | Coincide con |
|---|---|
^ | Inicio de línea |
$ | Fin de línea |
. | Cualquier carácter excepto salto de línea (con opción m incluye salto de línea) |
[...] | Cualquier carácter entre corchetes |
[^...] | Cualquier carácter no entre corchetes |
\A | Inicio de toda la cadena |
\z | Fin de toda la cadena |
\Z | Fin de la cadena salvo terminador de línea final permitido |
re* | 0 o más ocurrencias de la expresión anterior |
re+ | 1 o más ocurrencias de la expresión anterior |
re? | 0 o 1 ocurrencia de la expresión anterior |
re{n} | Exactamente n ocurrencias |
re{n,} | n o más ocurrencias |
re{n,m} | Entre n y m ocurrencias |
a|b | a o b |
(re) | Agrupa y recuerda el texto coincidente |
(?:re) | Agrupa sin recordar el texto coincidente |
(?>re) | Coincide patrón independiente sin retroceso (backtracking) |
\w | Caracteres de palabra [a-zA-Z0-9_] |
\W | No caracteres de palabra |
\s | Espacio en blanco [\t\n\r\f] |
\S | No espacio en blanco |
\d | Dígitos [0-9] |
\D | No dígitos |
\b | Límite de palabra (fuera de corchetes) / retroceso 0x08 (dentro) |
\B | No límite de palabra |
\n, \t, etc. | Saltos de línea, tabulaciones, etc. |
\Q...\E | Escapa (cita) todos los caracteres entre \Q y \E |
Métodos Principales de la Clase Matcher
Métodos de Índice
| Método | Descripción |
|---|---|
start() | Índice de inicio de la coincidencia anterior |
start(int group) | Índice de inicio del subgrupo capturado |
end() | Índice tras el último carácter coincidente |
end(int group) | Índice tras el último carácter del subgrupo capturado |
Métodos de Estudio (Búsqueda)
| Método | Descripción |
|---|---|
lookingAt() | Intenta coincidir desde el inicio de la región |
find() | Busca la siguiente subsecuencia que coincida |
find(int start) | Busca a partir del índice especificado |
matches() | Intenta coincidir con toda la región |
Métodos de Reemplazo
| Método | Descripción |
|---|---|
appendReplacement(StringBuffer sb, String replacement) | Paso de anexar-y-reemplazar no terminal |
appendTail(StringBuffer sb) | Paso de anexar-y-reemplazar terminal |
replaceAll(String replacement) | Reemplaza todas las subsecuencias que coincidan |
replaceFirst(String replacement) | Reemplaza la primera subsecuencia que coincida |
quoteReplacement(String s) | Devuelve un literal de reemplazo para appendReplacement |
Ejemplo: Contar ocurrencias de "cat" con límites de palabra
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "\\bcat\\b";
private static final String INPUT = "cat cat cat cattie cat";
public static void main(String args[]) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
int count = 0;
while (m.find()) {
count++;
System.out.println("Coincidencia #" + count);
System.out.println("start(): " + m.start());
System.out.println("end(): " + m.end());
}
}
}
Salida:
Coincidencia #1 start(): 0 end(): 3 Coincidencia #2 start(): 4 end(): 7 Coincidencia #3 start(): 8 end(): 11 Coincidencia #4 start(): 19 end(): 22
El uso de \b asegura que solo se cuente "cat" como palabra completa, no como subcadena de "cattie".
Diferencia entre matches() y lookingAt()
matches() requiere que toda la cadena coincida; lookingAt() solo verifica el inicio.
Pattern pattern = Pattern.compile("foo");
Matcher matcher = pattern.matcher("fooooooooooooooooo");
System.out.println("lookingAt(): " + matcher.lookingAt()); // true
System.out.println("matches(): " + matcher.matches()); // false
Ejemplo: replaceAll y replaceFirst
String REGEX = "dog";
String INPUT = "The dog says meow. All dogs say meow.";
String REPLACE = "cat";
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
Salida: The cat says meow. All cats say meow.
Ejemplo: appendReplacement y appendTail
String REGEX = "a*b";
String INPUT = "aabfooaabfooabfoob";
String REPLACE = "-";
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
Salida: -foo-foo-foo-
Métodos de PatternSyntaxException
| Método | Descripción |
|---|---|
getDescription() | Descripción del error |
getIndex() | Índice del error |
getPattern() | Patrón erróneo |
getMessage() | Mensaje multilínea con detalles completos |
Java
- Expresiones, sentencias y bloques en C#: Guía completa con ejemplos prácticos
- Dominar Operadores en Java: Tipos, Sintaxis y Ejemplos Prácticos
- Entender Expresiones, Sentencias y Bloques en Java
- Comentarios en Java: Tipos, Uso y Mejores Prácticas
- Dominar el Bucle for Mejorado en Java: Sintaxis, Ejemplos y Mejores Prácticas
- Dominar Strings en Java: Creación, Métodos y Mejores Prácticas
- Dominando interfaces en Java: Conceptos, implementación y mejores prácticas
- Dominando Try‑with‑Resources en Java: Gestión automática de recursos explicada
- Anotaciones en Java explicadas: Tipos, ubicación y ejemplos prácticos
- Aserciones en Java: Guía práctica para detectar bugs y asegurar fiabilidad del código
- Dominando Expresiones Lambda en Java: Desde Básicos hasta Stream API