Java – Expresiones regulares

Las expresiones regulares de Java viven en java.util.regex y tienen dos particularidades que no están en otros lenguajes: la barra invertida hay que duplicarla, y por omisión \w no reconoce los acentos.

La doble barra

"2026-10-08".matches("\\d{4}-\\d{2}-\\d{2}")
salidatrue
Esa doble barra es de Java, no de la expresión regular. La expresión es \d4; lo que pasa es que en una cadena de Java \ ya significa algo, así que hay que escribirla dos veces para que llegue una. Es el motivo del 90 % de los «no me funciona la regex» al venir de otro lenguaje. Desde Java 15 puedes usar un bloque de texto para escribirla tal cual.

Buscar todas las coincidencias

Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("la fecha 2026-10-08 y la 2025-01-31");

while (m.find()) {
    System.out.println("  " + m.group() + " -> año " + m.group(1)
                     + ", mes " + m.group(2) + " en la posición " + m.start());
}
salida2026-10-08 -> año 2026, mes 10 en la posición 9
  2025-01-31 -> año 2025, mes 01 en la posición 25

matches exige que toda la cadena encaje; find busca un trozo y se puede llamar en bucle. Confundirlos es el segundo error clásico. group(0) —o group()— es lo que encajó entero y del 1 en adelante van los paréntesis, de izquierda a derecha.

Compila el patrón una sola vez. String.matches compila la expresión en cada llamada. Dentro de un bucle, saca el Pattern.compile fuera y guárdalo en una constante static final: es la optimización más rentable de esta página.

Grupos con nombre

Matcher mc = Pattern.compile("(?<anio>\\d{4})-(?<mes>\\d{2})").matcher("2026-10");
if (mc.matches()) {
    System.out.println("anio=" + mc.group("anio") + " mes=" + mc.group("mes"));
}
salidaanio=2026 mes=10

Mucho mejor que contar paréntesis, sobre todo cuando mañana alguien añada uno en medio. Pero cuidado con el nombre:

Pattern.compile("(?<año>\\d{4})");
salidaPatternSyntaxException: named capturing group is missing trailing '>'

Los nombres de grupo en Java solo admiten letras del inglés y dígitos, y tienen que empezar por letra. Nada de eñes ni de acentos, y el mensaje de error no lo dice: se limita a quejarse de que falta el >.

Reemplazar y partir

System.out.println("uno, dos,tres".replaceAll("\\s*,\\s*", " | "));
System.out.println(Arrays.toString("a1b22c333d".split("\\d+")));
salidauno | dos | tres
[a, b, c, d]

En el reemplazo, $1 mete lo que capturó el primer grupo. Y si el texto de reemplazo viene de fuera, Matcher.quoteReplacement evita que un $ suelto lo rompa.

Las banderas, y la de los acentos

System.out.println(Pattern.compile("hola", Pattern.CASE_INSENSITIVE)
                          .matcher("HOLA mundo").find());

System.out.println("añil".matches("\\w+"));

System.out.println(Pattern.compile("\\w+", Pattern.UNICODE_CHARACTER_CLASS)
                          .matcher("añil").matches());
salidatrue
false
true
Ese false es importante si escribes en español. Por omisión, \w en Java significa [a-zA-Z0-9_] y deja fuera la eñe y los acentos; lo mismo le pasa a \b y a \s con los espacios raros. Se arregla con UNICODE_CHARACTER_CLASS, o escribiendo (?U) al principio del patrón. Un validador de nombres hecho con \w+ rechaza a cualquiera que se llame Muñoz.
BanderaQué hace
CASE_INSENSITIVEignora mayúsculas (solo ASCII si no añades UNICODE_CASE)
UNICODE_CHARACTER_CLASS\w, \d y \s entienden Unicode
MULTILINE^ y $ valen en cada línea
DOTALLel punto también encaja con el salto de línea
COMMENTSpermite espacios y comentarios dentro del patrón

Cuando el patrón está mal

salidaPatternSyntaxException: Unclosed group

PatternSyntaxException es unchecked: el compilador no te obliga a capturarla, así que un patrón mal escrito que venga de un archivo de configuración revienta en ejecución. Si la expresión no es una constante tuya, compílala dentro de un try.

Más información en inglés: Regular expressions in Java.

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.