Expressions regulars
Una expressió regular (regular expression, regex) és un patró que descriu un conjunt de cadenes. Serveix per validar dades, buscar text i substituir-lo, i la seva sintaxi és pràcticament la mateixa a Java, JavaScript, Python o els gestors de bases de dades.
Comprovar si un DNI té vuit xifres i una lletra:
String dni = "12345678Z";
boolean valid = dni.matches("\\d{8}[A-Z]"); // true
Fixa’t en la doble barra invertida. El patró és \d{8}[A-Z], però com que a Java viu dins d’un String, cada \ s’ha d’escriure \\. És l’error més freqüent quan es copia un patró d’una pàgina web.
matches() o find()
Aquesta distinció és la font principal de confusió:
matches()exigeix que tota la cadena encaixi amb el patró.find()busca la primera aparició del patró dins de la cadena, i cada crida següent busca la següent.
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("hi ha 3 gats i 12 gossos");
m.matches(); // false: la cadena sencera no són xifres
m.find(); // true, m.group() és "3"
m.find(); // true, m.group() és "12"
m.find(); // false: no n'hi ha més
Si el que vols és validar, matches(). Si el que vols és extreure, find().
Pattern i Matcher
El treball es reparteix entre dues classes:
Patternés el patró ja compilat. Compilar té un cost, i elPatternes pot reutilitzar tantes vegades com calgui.Matcherés l’intent d’aplicar un patró a una cadena concreta. En necessites un per cada text.
private static final Pattern DNI = Pattern.compile("\\d{8}[A-Z]"); // una sola vegada
public static boolean esValid(String text) {
return DNI.matcher(text).matches();
}
Els mètodes de String (text.matches(...), text.replaceAll(...), text.split(...)) compilen el patró a cada crida. Van bé per a un ús puntual, però dins d’un bucle val més compilar el Pattern a fora.
Grups
Els parèntesis marquen parts del patró que vols recuperar per separat. Es numeren d’esquerra a dreta començant per 1, i el grup 0 és sempre la coincidència sencera.
Pattern p = Pattern.compile("(\\d{2})/(\\d{2})/(\\d{4})");
Matcher m = p.matcher("22/09/2026");
if (m.matches()) {
String dia = m.group(1); // "22"
String mes = m.group(2); // "09"
String any = m.group(3); // "2026"
}
Comptar parèntesis es fa insostenible de seguida. Els grups amb nom eviten el problema:
Pattern p = Pattern.compile("(?<dia>\\d{2})/(?<mes>\\d{2})/(?<any>\\d{4})");
Matcher m = p.matcher("22/09/2026");
if (m.matches()) {
String any = m.group("any");
}
Comprova sempre que matches() o find() ha retornat true abans de cridar group(). Si no, obtindràs un IllegalStateException.
Substituir i separar
"hi ha 3 gats".replaceAll("\\d+", "molts"); // "hi ha molts gats"
"a1b22c333".split("\\d+"); // ["a", "b", "c"]
A la substitució pots referenciar els grups capturats amb $1, $2:
"22/09/2026".replaceAll("(\\d{2})/(\\d{2})/(\\d{4})", "$3-$2-$1"); // "2026-09-22"
Sintaxi bàsica
| Patró | Encaixa amb |
|---|---|
. | Qualsevol caràcter |
\d, \w, \s | Xifra, caràcter de paraula, espai en blanc |
\D, \W, \S | El contrari de cadascun |
[abc], [a-z], [^abc] | Un dels caràcters, un del rang, qualsevol excepte aquests |
*, +, ? | Zero o més, una o més, cap o una |
{n}, {n,}, {n,m} | Exactament n, com a mínim n, entre n i m |
a|b | a o bé b |
^, $ | Principi i final de la cadena |
(...) | Grup de captura |
Els quantificadors són voraços per defecte: agafen tot el que poden. Afegint-hi ? es tornen mandrosos i agafen el mínim. Amb el text <a><b>, el patró <.*> captura <a><b> sencer, mentre que <.*?> captura només <a>.
La documentació de Pattern té la taula completa de construccions acceptades.
Referències
- Pattern (Java SE 25 API)
- Capturing Groups (The Java Tutorials)
- Regex101: provador interactiu amb explicació del patró