Cos'è l'espressione regolare RegEx?
In effetti, un'espressione regolare (RegEx in Java) è un modello per la ricerca di una stringa nel testo. In Java la rappresentazione iniziale di questo pattern è sempre una stringa, cioè un oggetto della classe String. Tuttavia, non tutte le stringhe possono essere compilate in un'espressione regolare, solo quelle che seguono le regole per scrivere un'espressione regolare: la sintassi definita nelle specifiche del linguaggio. Per scrivere un'espressione regolare, vengono utilizzati caratteri alfabetici e numerici, nonché metacaratteri, caratteri che hanno un significato speciale nella sintassi delle espressioni regolari. Per esempio:String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;
Creazione di espressioni regolari in Java
Per creare una RegEx in Java è necessario seguire due semplici passaggi:- scriverlo come una stringa utilizzando la sintassi delle espressioni regolari;
- compilare questa stringa in un'espressione regolare;
Pattern
. Per fare ciò è necessario chiamare uno dei due metodi statici disponibili nella classe compile
. Il primo metodo accetta un argomento, una stringa letterale di un'espressione regolare, e il secondo, più un altro parametro che attiva la modalità per confrontare il modello con il testo:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
L'elenco dei possibili valori dei parametri flags
è definito nella classe Pattern
ed è a nostra disposizione come variabili di classe statiche. Per esempio:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//searching for matches with the pattern will be done case-insensitively.
Essenzialmente, la classe Pattern
è un costruttore di espressioni regolari. Dietro le quinte, il metodo compile
chiama il costruttore privato della classe Pattern
per creare una vista compilata. Questo metodo di creazione di un'istanza di modello è implementato con l'obiettivo di crearla come oggetto immutabile. Durante la creazione viene eseguito un controllo della sintassi dell'espressione regolare. Se sono presenti errori nella riga, viene generata un'eccezione PatternSyntaxException
.
Sintassi delle espressioni regolari
La sintassi delle espressioni regolari si basa sull'uso di simboli<([{\^-=$!|]})?*+.>
, che possono essere combinati con caratteri alfabetici. A seconda del loro ruolo, possono essere suddivisi in diversi gruppi:
Metacarattere | Scopo |
---|---|
^ | inizio riga |
$ | fine della riga |
\B | confine di parola |
\B | non un limite di parole |
\UN | inizio dell'input |
\G | fine della partita precedente |
\Z | fine dell'input |
\z | fine dell'input |
Metacarattere | Scopo |
---|---|
\D | simbolo digitale |
\D | carattere non numerico |
\S | carattere spaziale |
\S | carattere diverso da spazi bianchi |
\w | carattere alfanumerico o carattere di sottolineatura |
\W | qualsiasi carattere diverso da quelli alfabetici, numerici o di sottolineatura |
. | qualsiasi carattere |
Metacarattere | Scopo |
---|---|
\T | carattere di tabulazione |
\N | carattere di nuova riga |
\R | carattere di ritorno a capo |
\F | vai alla nuova pagina |
\u0085 | carattere della riga successiva |
\u2028 | carattere separatore di riga |
\u2029 | simbolo separatore di paragrafo |
Metacarattere | Scopo |
---|---|
[aBC] | uno qualsiasi dei precedenti (a, b o c) |
[^abc] | qualsiasi diverso da quelli elencati (non a, b, c) |
[a-zA-Z] | fusione di intervalli (i caratteri latini dalla a alla z non fanno distinzione tra maiuscole e minuscole) |
[annuncio[mp]] | concatenazione di caratteri (da a a d e da m a p) |
[az&&[def]] | intersezione di simboli (simboli d,e,f) |
[az&&[^bc]] | sottraendo caratteri (caratteri a, dz) |
Metacarattere | Scopo |
---|---|
? | uno o mancante |
* | zero o più volte |
+ | una o più volte |
{N} | n volte |
{N,} | n volte o più |
{n,m} | non meno di n volte e non più di m volte |
Modalità quantificatore goloso
Una caratteristica speciale dei quantificatori è la possibilità di usarli in diverse modalità: greedy, super-greedy e lazy. La modalità extra-greedy viene attivata aggiungendo il simbolo "+
" dopo il quantificatore e la modalità pigra aggiungendo il simbolo " ?
". Per esempio:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
Utilizzando questo modello come esempio, proviamo a capire come funzionano i quantificatori in diverse modalità. Per impostazione predefinita, il quantificatore funziona in modalità greedy. Ciò significa che cerca la corrispondenza più lunga possibile nella stringa. Come risultato dell'esecuzione di questo codice:
public static void main(String[] args) {
String text = "Egor Alla Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
otterremo il seguente output: Alla Alexa L'algoritmo di ricerca per un dato pattern " А.+а
" viene eseguito nella seguente sequenza:
-
Nello schema indicato, il primo carattere è la lettera russa
А
.Matcher
lo confronta con ogni carattere del testo, a partire dalla posizione zero. Alla posizione zero nel nostro testo c'è un simboloЕ
, quindiMatcher
attraversa i caratteri nel testo in sequenza finché non incontra una corrispondenza con il modello. Nel nostro esempio, questo è il simbolo nella posizione n. 5. -
Dopo che viene trovata una corrispondenza con il primo carattere del modello,
Matcher
controlla la corrispondenza con il secondo carattere del modello. Nel nostro caso, questo è il simbolo “.
”, che rappresenta qualsiasi carattere.Nella sesta posizione c'è il simbolo della lettera
л
. Naturalmente, corrisponde al modello "qualsiasi carattere". -
Matcher
passa al controllo del carattere successivo del pattern. Nel nostro modello, viene specificato utilizzando il.+
quantificatore “ ”. Poiché il numero di ripetizioni di "qualsiasi carattere" nello schema è una o più volte,Matcher
prende a turno il carattere successivo dalla stringa e ne controlla la conformità con lo schema, purché sia soddisfatta la condizione "qualsiasi carattere", nel nostro esempio - fino alla fine della riga ( dalla posizione n. 7 - n. 18 del testo).In effetti,
Matcher
cattura l'intera linea fino alla fine: è qui che si manifesta la sua "avidità". -
Dopo
Matcher
aver raggiunto la fine del testo e aver finito di controllare laА.+
parte “ ” del modello, Matcher inizia a controllare il resto del modello: il carattere della letteraа
. Poiché il testo in avanti è terminato, il controllo avviene in senso inverso, partendo dall'ultimo carattere: -
Matcher
"ricorda" il numero di ripetizioni nello schema ".+
" con cui ha raggiunto la fine del testo, quindi riduce il numero di ripetizioni di uno e controlla lo schema del testo finché non trova una corrispondenza:
Modalità quantificatore ultra-avido
Nella modalità super-greedy, il matcher funziona in modo simile al meccanismo della modalità greedy. La differenza è che quando prendi il testo fino alla fine della riga, non viene effettuata la ricerca all'indietro. Cioè, le prime tre fasi della modalità super-avida saranno simili alla modalità avida. Dopo aver catturato l'intera stringa, il matcher aggiunge il resto del modello e lo confronta con la stringa catturata. Nel nostro esempio, quando si esegue il metodo main con il pattern "А.++а
", non verrà trovata alcuna corrispondenza.
Modalità quantificatore pigro
-
In questa modalità, nella fase iniziale, come nella modalità greedy, si cerca una corrispondenza con il primo carattere del pattern:
-
Successivamente, cerca una corrispondenza con il carattere successivo nel modello, qualsiasi carattere:
-
A differenza della modalità greedy, la modalità lazy cerca la corrispondenza più breve nel testo, quindi dopo aver trovato una corrispondenza con il secondo carattere del modello, che è specificato da un punto e corrisponde al carattere nella posizione n. 6 del testo,
Matcher
controllerà se il testo corrisponde al resto dello schema: il carattere "а
" . -
Poiché non è stata trovata una corrispondenza con il modello nel testo (nella posizione n. 7 del testo c'è il simbolo “ “
л
),Matcher
aggiunge un altro “qualsiasi carattere” nel modello, poiché è specificato una o più volte, e confronta nuovamente il modello con il testo nelle posizioni dal n. 5 al n. 8: -
Nel nostro caso è stata trovata una corrispondenza, ma non è stata ancora raggiunta la fine del testo. Pertanto, dalla posizione n. 9, il controllo inizia cercando il primo carattere del pattern utilizzando un algoritmo simile e poi si ripete fino alla fine del testo.
main
quando si utilizza il А.+?а
modello " ", otterremo il seguente risultato: Alla Alexa Come si può vedere dal nostro esempio, quando si utilizzano diverse modalità di quantificazione per lo stesso modello, si ottengono risultati diversi. Pertanto, è necessario tenere conto di questa funzionalità e selezionare la modalità desiderata in base al risultato desiderato durante la ricerca.
Caratteri di escape nelle espressioni regolari
Poiché un'espressione regolare in Java, o più precisamente la sua rappresentazione iniziale, viene specificata utilizzando una stringa letterale, è necessario tenere conto delle regole della specifica Java che si riferiscono alle stringhe letterali. In particolare, il carattere barra rovesciata "\
" nelle stringhe letterali nel codice sorgente Java viene interpretato come un carattere di escape che avvisa il compilatore che il carattere che lo segue è un carattere speciale e deve essere interpretato in un modo speciale. Per esempio:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
Pertanto, nei valori letterali stringa che descrivono un'espressione regolare e utilizzano il \
carattere " " (ad esempio, per i metacaratteri), è necessario raddoppiarlo in modo che il compilatore bytecode Java non lo interpreti in modo diverso. Per esempio:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
Il carattere doppia barra rovesciata dovrebbe essere utilizzato anche per sfuggire ai caratteri speciali se intendiamo utilizzarli come caratteri "normali". Per esempio:
String regex = "How\\?"; // template for searching the string "How?"
Metodi della classe Pattern
La classePattern
dispone di altri metodi per lavorare con le espressioni regolari: String pattern()
– restituisce la rappresentazione stringa originale dell'espressione regolare da cui è stato creato l'oggetto Pattern
:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)
– consente di verificare l'espressione regolare passata nel parametro regex rispetto al testo passato nel parametro input
. Restituisce: true – se il testo corrisponde al modello; falso – altrimenti; Esempio:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla Alexander"));//false
int flags()
– restituisce i flags
valori dei parametri del modello impostati al momento della creazione oppure 0 se questo parametro non è stato impostato. Esempio:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)
– suddivide il testo passato come parametro in un array di elementi String
. Il parametro limit
determina il numero massimo di corrispondenze che vengono cercate nel testo:
- quando
limit>0
–limit-1
viene eseguita la ricerca delle corrispondenze; - at
limit<0
– cerca tutte le corrispondenze nel testo - quando
limit=0
– cerca tutte le corrispondenze nel testo, mentre le righe vuote alla fine dell'array vengono scartate;
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("\\s");
String[] strings = pattern.split(text,2);
for (String s : strings) {
System.out.println(s);
}
System.out.println("---------");
String[] strings1 = pattern.split(text);
for (String s : strings1) {
System.out.println(s);
}
}
Output della console: Egor Alla Anna -------- Egor Alla Anna Di seguito considereremo un altro metodo di classe per creare un oggetto Matcher
.
Metodi della classe Matcher
Matcher
è una classe da cui viene creato un oggetto per cercare modelli. Matcher
– questo è un “motore di ricerca”, un “motore” di espressioni regolari. Per effettuare la ricerca è necessario fornirgli due cose: uno schema di ricerca e un "indirizzo" a cui effettuare la ricerca. Per creare un oggetto Matcher
nella classe viene fornito il seguente metodo Pattern
: рublic Matcher matcher(CharSequence input)
Come argomento il metodo prende una sequenza di caratteri in cui verrà effettuata la ricerca. Questi sono oggetti di classi che implementano l'interfaccia CharSequence
. String
Puoi passare non solo , ma anche , StringBuffer
e StringBuilder
come argomento . Il modello di ricerca è l'oggetto della classe su cui viene chiamato il metodo . Esempio di creazione di un matcher: Segment
CharBuffer
Pattern
matcher
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using the pattern "a*b"
Ora, con l'aiuto del nostro "motore di ricerca", possiamo cercare corrispondenze, scoprire la posizione della corrispondenza nel testo e sostituire il testo utilizzando i metodi della classe. Il metodo boolean find()
cerca la corrispondenza successiva nel testo con il modello. Usando questo metodo e l'operatore loop, puoi analizzare l'intero testo secondo il modello degli eventi (eseguire le operazioni necessarie quando si verifica un evento, trovando una corrispondenza nel testo). Ad esempio, utilizzando i metodi di questa classe, int start()
è int end()
possibile determinare le posizioni delle corrispondenze nel testo e, utilizzando i metodi String replaceFirst(String replacement)
, String replaceAll(String replacement)
sostituire le corrispondenze nel testo con un altro testo sostitutivo. Esempio:
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found" + text.substring(start,end) + " с "+ start + " By " + (end-1) + "position");
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Olga"));
System.out.println(text);
}
Output del programma: È stata trovata una corrispondenza Alla dalla 5a all'8a posizione È stata trovata una corrispondenza Anna dalla 10a alla 13a posizione Egor Ira Anna Egor Olga Olga Egor Alla Anna Dall'esempio è chiaro che i metodi replaceFirst
creano replaceAll
un nuovo oggetto String
- una stringa, che è il testo di origine in cui le corrispondenze con template vengono sostituite con il testo passato al metodo come argomento. Inoltre, il metodo replaceFirst
sostituisce solo la prima corrispondenza e replaceAll
tutte le corrispondenze del test. Il testo originale rimane invariato. L'uso di altri metodi di classe Matcher
, nonché esempi di espressioni regolari, possono essere trovati in questa serie di articoli . Le operazioni più comuni con le espressioni regolari quando si lavora con il testo provengono dalle classi Pattern
e Matcher
sono integrate nel file String
. Questi sono metodi come split
, matches
, replaceFirst
, replaceAll
. Ma in realtà, "sotto il cofano" usano Pattern
e Matcher
. Pertanto, se è necessario sostituire testo o confrontare stringhe in un programma senza scrivere codice non necessario, utilizzare i metodi di String
. Se hai bisogno di funzionalità avanzate, pensa alle classi Pattern
e ai file Matcher
.
Conclusione
Un'espressione regolare viene descritta in un programma Java utilizzando stringhe che corrispondono a un modello definito dalle regole. Quando il codice viene eseguito, Java ricompila questa stringa in un oggetto di classePattern
e utilizza l'oggetto di classe Matcher
per trovare corrispondenze nel testo. Come ho detto all’inizio, molto spesso le espressioni regolari vengono messe da parte per dopo, considerato un argomento difficile. Tuttavia, se si comprendono le basi della sintassi, dei metacaratteri, dell'escape e si studiano esempi di espressioni regolari, risultano molto più semplici di quanto sembri a prima vista.
GO TO FULL VERSION