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 grupab
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).
- Si afegim
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 laA
a laZ
.+
: 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 formatdd/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 objectePattern
. És el primer pas abans de poder buscar coincidències ambMatcher
. -
matcher(CharSequence input)
Crea un objecteMatcher
associat al text que volem analitzar. El text pot ser unaString
o qualsevol objecte que implementeCharSequence
. -
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 unMatcher
. -
split(CharSequence input)
Divideix el text segons el patró i retorna un array deString
amb les parts resultants. És una alternativa aString.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. Retornatrue
si en troba una ifalse
quan ja no n’hi ha més. Normalment s’utilitza dins d’un buclewhile
. -
group()
Retorna la subcadena que ha coincidit amb el patró en la cerca actual. S’utilitza després d’unfind()
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 ambfind()
, extrau ambgroup()
i mostra les posicions ambstart()
iend()
.
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()
(dePattern
) – Tracta un text literal com una expressió regular, evitant que els seus caràcters especials s’interpreten.pattern()
(deMatcher
) – Retorna elPattern
associat alMatcher
.
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.