Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 el Pattern es 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, \sXifra, caràcter de paraula, espai en blanc
\D, \W, \SEl 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|ba 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

Last change: , commit: 87dfa51