Expressions Regulars en Java

Les expressions regulars (regex) són seqüències de caràcters que defineixen patrons per a cercar, validar i manipular cadenes de text. A Java, són molt útils per a identificar patrons complexos en les cadenes, com ara números de telèfon, adreces de correu electrònic o valors específics.

Usos Comuns de les Expressions Regulars

Alguns exemples d’ús de les expressions regulars són:

  • Validació de formats: Comprovar que una data siga en format dd/mm/yyyy o que un NIF (Número d’Identificació Fiscal) seguisca el format correcte.
  • Validació de correu electrònic: Verificar que una adreça de correu complisca amb un format estàndard.
  • Validació de contrasenyes: Assegurar-se que una contrasenya continga majúscules, minúscules, números i símbols.
  • Extracció de dades: Buscar i extraure números de telèfon, codis postals o qualsevol altra informació que complisca un patró determinat.
  • Cerca de patrons: Trobar i comptar quantes vegades es repeteix un fragment dins d’una cadena.

Funcionament Bàsic de les Expressions Regulars

Les expressions regulars recorren una cadena d’esquerra a dreta, buscant coincidències amb el patró definit. Quan un caràcter de la cadena compleix amb el patró, aquest caràcter ja no torna a considerar-se per a futures comprovacions en la mateixa cerca.

Hi ha dos enfocaments principals en la comparació de patrons amb cadenes:

  • Trobar coincidències parcials: Determinar si una part de la cadena compleix amb el patró. Per exemple, trobar una data en format dd/mm/yyyy dins d’una cadena com “Hui és 12/02/2017”.
  • Coincidència exacta: Verificar que tota la cadena complisca exactament amb el patró donat. Per exemple, comprovar si “12/02/2017” és exactament una data sense text addicional.

Metacaràcters i Quantificadors en Expressions Regulars (Java)

Metacaràcters més comuns

Els metacaràcters són símbols especials que defineixen el comportament d’un patró dins d’una expressió regular.

Signe Explicació  
. Qualsevol caràcter (excepte salt de línia)  
^ Inici de la cadena  
$ Final de la cadena  
[abc] Qualsevol dels caràcters a, b o c  
[^abc] Qualsevol caràcter excepte a, b o c  
[a-z] Qualsevol lletra entre a i z  
**A B** Coincideix amb A o amb B
\d Qualsevol dígit (0–9)  
\D Qualsevol caràcter que no siga un dígit  
\s Qualsevol espai en blanc (espai, tabulador o salt de línia)  
\S Qualsevol caràcter que no siga espai en blanc  
\w Qualsevol lletra, número o subratllat (_)  
\W Qualsevol caràcter que no siga lletra, número ni subratllat  

Nota important sobre ^ i $

Quan posem ^ al principi del patró i $ al final, li estem dient al motor de regex que tota la cadena ha de coincidir exactament amb el patró, no sols una part.

És a dir:

Cas Patró Coincideix amb
Sense ^ i $ \\d{3} qualsevol part de text que tinga 3 dígits seguits
Amb ^ ^\\d{3} si la cadena comença amb 3 dígits
Amb $ \\d{3}$ si la cadena acaba amb 3 dígits
Amb ^ i $ ^\\d{3}$ si tota la cadena són exactament 3 dígits

Quantificadors

Els quantificadors indiquen quantes vegades pot aparéixer un element dins del patró. S’apliquen sobre el caràcter o grup immediatament anterior.

Quantificador Significat Exemple Coincideix amb No coincideix amb
* Zero o més repeticions a* "", "a", "aa", "aaa" "b"
+ Una o més repeticions a+ "a", "aa", "aaa" ""
? Zero o una repetició a? "", "a" "aa"
{X} Exactament X repeticions a{3} "aaa" "aa", "aaaa"
{X,} Com a mínim X repeticions a{2,} "aa", "aaa", "aaaa" "a"
{X,Y} Entre X i Y repeticions a{1,3} "a", "aa", "aaa" "", "aaaa"

Cal rindre en compte:

  • Els quantificadors actuen sobre un caràcter, conjunt o grup:

    • [A-Z]+ → una o més majúscules seguides
    • (ab){2} → el grup ab repetit dues vegades (abab)
  • Per defecte són “voraces” (greedy), és a dir, intenten casar el màxim possible.

    • Si afegim ? darrere (+?, *?, {x,y}?), passen a ser reticents (busquen el mínim possible).

Exemples d’Expressions Regulars

1. Validar un dígit


String regex = "^\\d$";
  • ^: Indica l’inici de la cadena, (exigeix coincidència de tota la cadena junt amb $).
  • \\d: Representa qualsevol dígit del 0 al 9.
  • $: Indica el final de la cadena (tanca la coincidència exacta amb ^).

Exemple:

  • "5": Vàlid, ja que és un únic dígit.
  • "a": No vàlid, ja que no és un dígit.
  • "12": No vàlid, ja que conté més d’un dígit.

2. Validar una paraula de lletres majúscules


String regex = "^[A-Z]+$";
  • ^: Inici de la cadena.
  • [A-Z]: Qualsevol lletra majúscula de la A a la Z.
  • +: Almenys una o més repeticions de lletres majúscules.
  • $: Final de la cadena.

Exemple:

  • "HELLO": Vàlid, només conté lletres majúscules.
  • "Hello": No vàlid, conté lletres minúscules.
  • "123": No vàlid, no conté cap lletra.

3. Validar un número enter positiu de fins a 3 dígits


String regex = "^[1-9]\\d{0,2}$";
  • ^: Inici de la cadena.
  • [1-9]: El primer dígit ha de ser entre 1 i 9 (per evitar zeros al davant).
  • \\d{0,2}: Pot tenir de 0 a 2 dígits addicionals.
  • $: Final de la cadena.

Exemple:

  • "5": Vàlid, ja que és un número de 1 dígit.
  • "123": Vàlid, ja que és un número de 3 dígits.
  • "012": No vàlid, comença amb un zero.
  • "1000": No vàlid, ja que conté més de 3 dígits.

4. Validar una adreça de correu electrònic senzilla

Ací tens l’explicació actualitzada per al patró:

String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
  • ^: Inici de la cadena.
  • [A-Za-z0-9+_.-]+: Part d’usuari abans de l’@ (lletres, dígits i + _ . -).
  • @: Separador entre usuari i domini.
  • [A-Za-z0-9.-]+: Domini (etiquetes amb lletres/dígits, punts i guions).
  • \\.[A-Za-z]{2,}: Punt seguit d’un TLD de 2 o més lletres (p. ex. .com, .es, .edu, …).
  • $: Final de la cadena.

Exemple:

  • "joan123@gmail.com": Vàlid.
  • "maria@universitat": No vàlid, falta el domini després del punt.
  • "pere@empresa.net": Vàlid.
  • "@gmail.com": No vàlid, falta la part de l’usuari.

5. Validar una data en format dd/mm/yyyy


String regex = "^(0[1-9]|[12]\\d|3[01])/(0[1-9]|1[0-2])/\\d{4}$";
  • ^: Inici de la cadena.
  • (0[1-9]|[12]\\d|3[01]): Dies de l’1 al 31.
  • /: Separador de la data.
  • (0[1-9]|1[0-2]): Mesos de l’1 al 12.
  • /: Separador de la data.
  • \\d{4}: Any de quatre dígits.
  • $: Final de la cadena.

Exemple:

  • "12/02/2024": Vàlid.
  • "31/04/2024": Vàlid, tot i que no és una data real (no comprova els dies del mes).
  • "01/13/2024": No vàlid, no existeix el mes 13.
  • "1/2/2024": No vàlid, falta un zero per mantenir el format dd/mm/yyyy.

6. Validar un número de telèfon en format internacional


String regex = "^\\+[0-9]{1,3} ?[0-9]{6,14}$";
  • ^\\+: Comença amb el símbol +.
  • [0-9]{1,3}: Codi de país, d’1 a 3 dígits.
  • ?: Espai opcional.
  • [0-9]{6,14}: De 6 a 14 dígits per al número de telèfon.
  • $: Final de la cadena.

Exemple:

  • "+34 123456789": Vàlid.
  • "+123456789": Vàlid.
  • "123456789": No vàlid, falta el + del codi de país.
  • "+1 12345": No vàlid, massa pocs dígits.

7. Validar una contrasenya amb requisits de seguretat


String regex = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[@#$%!]).{8,}$";
  • ^: Inici de la cadena.
  • (?=.*[A-Z]): Almenys una lletra majúscula.
  • (?=.*[a-z]): Almenys una lletra minúscula.
  • (?=.*\\d): Almenys un dígit.
  • (?=.*[@#$%!]): Almenys un dels caràcters especials: @, #, $, %, !.
  • .{8,}: La contrasenya ha de tenir almenys 8 caràcters.
  • $: Final de la cadena.

Exemple:

  • "Password123!": Vàlid.
  • "password": No vàlid, falta una majúscula, un dígit i un caràcter especial.
  • "PASSWORD123": No vàlid, falta un caràcter especial i una minúscula.
  • "Pass1!": No vàlid, massa curta.

Pattern i Matcher

Les classes Pattern i Matcher en Java ens permeten treballar amb expressions regulars, és a dir, seqüències de caràcters que defineixen patrons per a cercar, validar o manipular textos d’una manera eficient i flexible.


Classe Pattern

La classe Pattern representa una expressió regular compilada, és a dir, un patró ja preparat per ser utilitzat. A partir d’aquest objecte podem crear instàncies de Matcher per cercar coincidències dins d’un text.

Mètodes principals de Pattern

  • Pattern.compile(String regex) Compila una expressió regular en un objecte Pattern. És el primer pas abans de poder buscar coincidències amb Matcher.

  • matcher(CharSequence input) Crea un objecte Matcher associat al text que volem analitzar. El text pot ser una String o qualsevol objecte que implemente CharSequence.

  • Pattern.matches(String regex, CharSequence input) Mètode estàtic que comprova si tota la cadena coincideix exactament amb el patró. És útil per fer validacions senzilles sense necessitat de crear un Matcher.

  • split(CharSequence input) Divideix el text segons el patró i retorna un array de String amb les parts resultants. És una alternativa a String.split(), però amb més potència gràcies a les expressions regulars.


Classe Matcher

La classe Matcher s’obté a partir d’un objecte Pattern i permet buscar coincidències, extraure fragments o substituir-los dins d’una cadena de text. Ofereix mètodes per a recórrer els resultats i treballar amb ells d’una manera molt flexible.

Mètodes principals de Matcher

  • matches() Comprova si tota la cadena compleix amb el patró.

  • find() Busca la propera coincidència dins del text. Retorna true si en troba una i false quan ja no n’hi ha més. Normalment s’utilitza dins d’un bucle while.

  • group() Retorna la subcadena que ha coincidit amb el patró en la cerca actual. S’utilitza després d’un find() per obtindre el text concret trobat.

  • start() Indica la posició inicial (índex) de la coincidència dins del text.

  • end() Indica la posició final (índex) de la coincidència dins del text.

  • replaceAll(String replacement) Substitueix totes les coincidències del patró dins del text per la cadena indicada. És molt útil per censurar, corregir o normalitzar textos automàticament.


Exemples pràctics

Exemple 1: Extracció de números de telèfon

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class ExtractorDeTelefons {
    public static void main(String[] args) {
        String text = "El meu número de telèfon és 123-456-789. El de casa és 964-123-456";
        String regex = "\\d{3}-\\d{3}-\\d{3}";

        Pattern objectePattern = Pattern.compile(regex);
        Matcher objecteMatcher = objectePattern.matcher(text);

        while (objecteMatcher.find()) {
            String phoneNumber = objecteMatcher.group();
            System.out.println("El número de telèfon trobat és: " + phoneNumber);
            System.out.println("Inici: " + objecteMatcher.start() + ", Fi: " + objecteMatcher.end());
        }
    }
}

Què fa el codi?

  • Pattern objectePattern = Pattern.compile(regex); Compila l’expressió regular \\d{3}-\\d{3}-\\d{3} en un patró reutilitzable. (“Pattern” és el *motlle del que busquem).*

  • Matcher objecteMatcher = objectePattern.matcher(text); Crea un cercador sobre el text que aplicarà el patró. (“Matcher” és l’operari* que recorre el text i troba coincidències).*

  • while (objecteMatcher.find()) { ... } Va buscant la següent coincidència del patró dins del text.

  • objecteMatcher.group() Retorna el fragment trobat que compleix el patró (p. ex. 123-456-789).

  • objecteMatcher.start() / objecteMatcher.end() Donen les posicions (índex inicial i final) de la coincidència dins del text.

En resum:

  • Pattern defineix i compila què busques.
  • Matcher s’encarrega de on i com ho busques: recorre el text amb find(), extrau amb group() i mostra les posicions amb start() i end().

Exemple 2: Validació de correu electrònic

import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class ValidarCorreu {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Introdueix un correu electrònic:");
        String email = sc.nextLine();
        String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);

        if (matcher.matches()) {
            System.out.println("L'adreça de correu és vàlida.");
        } else {
            System.out.println("L'adreça de correu NO és vàlida.");
        }
        sc.close();
    }
}

El mètode matches() comprova si la cadena email coincideix completament amb el patró d’una adreça de correu vàlida.


Exemple 3: Reemplaçament de paraules ofensives

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Censura {
    public static void main(String[] args) {
        String frase = "Eres un datil i un abobat.";
        String regex = "(datil|abobat)";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(frase);

        String fraseCensurada = matcher.replaceAll("****");
        System.out.println("CENSURAT!!!!: " + fraseCensurada);
    }
}

L’exemple utilitza replaceAll() per substituir totes les coincidències de les paraules “datil” i “abobat” per “**”.


Altres mètodes útils

  • lookingAt() – Verifica si la cadena comença amb el patró, sense exigir que tota coincidisca.
  • quote() (de Pattern) – Tracta un text literal com una expressió regular, evitant que els seus caràcters especials s’interpreten.
  • pattern() (de Matcher) – Retorna el Pattern associat al Matcher.

En conjunt, les classes Pattern i Matcher fan que el treball amb expressions regulars a Java siga potent, precís i molt versàtil, permetent des de validacions simples fins a processaments avançats de text.



Table of contents