JavaRush /Java Blog /Random-IT /Espressioni regolari in Java (RegEx)

Espressioni regolari in Java (RegEx)

Pubblicato nel gruppo Random-IT
Le espressioni regolari sono un argomento che i programmatori, anche quelli esperti, spesso rimandano a più tardi. Tuttavia, la maggior parte degli sviluppatori Java prima o poi dovrà occuparsi dell'elaborazione del testo. Molto spesso - con operazioni di ricerca nel testo e modifica. Senza le espressioni regolari, il codice di programma produttivo e compatto associato all'elaborazione del testo è semplicemente impensabile. Quindi smettila di rimandare, occupiamoci dei "clienti abituali" adesso. Questo non è un compito così difficile.

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:
  1. scriverlo come una stringa utilizzando la sintassi delle espressioni regolari;
  2. compilare questa stringa in un'espressione regolare;
Il lavoro con le espressioni regolari in qualsiasi programma Java inizia con la creazione di un oggetto di classe 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 Patterned è 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 compilechiama il costruttore privato della classe Patternper 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:
1. Metacaratteri per la corrispondenza dei limiti di riga o del testo
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
2. Metacaratteri per la ricerca di classi di caratteri
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
3. Metacaratteri per la ricerca di simboli di modifica del testo
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
4. Metacaratteri per raggruppare i caratteri
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)
5. Metasimboli per indicare il numero di caratteri - quantificatori. Il quantificatore viene sempre dopo un carattere o un gruppo di caratteri.
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:
  1. Nello schema indicato, il primo carattere è la lettera russa А. Matcherlo confronta con ogni carattere del testo, a partire dalla posizione zero. Alla posizione zero nel nostro testo c'è un simbolo Е, quindi Matcherattraversa i caratteri nel testo in sequenza finché non incontra una corrispondenza con il modello. Nel nostro esempio, questo è il simbolo nella posizione n. 5.

    Espressioni regolari in Java - 2
  2. Dopo che viene trovata una corrispondenza con il primo carattere del modello, Matchercontrolla la corrispondenza con il secondo carattere del modello. Nel nostro caso, questo è il simbolo “ .”, che rappresenta qualsiasi carattere.

    Espressioni regolari in Java - 3

    Nella sesta posizione c'è il simbolo della lettera л. Naturalmente, corrisponde al modello "qualsiasi carattere".

  3. Matcherpassa 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, Matcherprende 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).

    Espressioni regolari in Java - 4

    In effetti, Matchercattura l'intera linea fino alla fine: è qui che si manifesta la sua "avidità".

  4. Dopo Matcheraver 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:

    Espressioni regolari in Java - 5
  5. 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: Espressioni regolari in Java - 6

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. Espressioni regolari in Java - 7

Modalità quantificatore pigro

  1. In questa modalità, nella fase iniziale, come nella modalità greedy, si cerca una corrispondenza con il primo carattere del pattern:

    Espressioni regolari in Java - 8
  2. Successivamente, cerca una corrispondenza con il carattere successivo nel modello, qualsiasi carattere:

    Espressioni regolari in Java - 9
  3. 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, Matchercontrollerà se il testo corrisponde al resto dello schema: il carattere " а" .

    Espressioni regolari in Java - 10
  4. Poiché non è stata trovata una corrispondenza con il modello nel testo (nella posizione n. 7 del testo c'è il simbolo “ “ л), Matcheraggiunge 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:

    Espressioni regolari in Java - 11
  5. 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.

    Espressioni regolari in Java - 12
Come risultato del metodo, mainquando 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 classe Patterndispone 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 flagsvalori 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 limitdetermina il numero massimo di corrispondenze che vengono cercate nel testo:
  • quando limit>0limit-1viene 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;
Esempio:
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 Matchernella 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. StringPuoi passare non solo , ma anche , StringBuffere StringBuildercome argomento . Il modello di ricerca è l'oggetto della classe su cui viene chiamato il metodo . Esempio di creazione di un matcher: SegmentCharBufferPatternmatcher
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 replaceFirstcreano replaceAllun 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 replaceFirstsostituisce solo la prima corrispondenza e replaceAlltutte 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 Patterne Matchersono integrate nel file String. Questi sono metodi come split, matches, replaceFirst, replaceAll. Ma in realtà, "sotto il cofano" usano Patterne 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 Patterne 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 classe Patterne utilizza l'oggetto di classe Matcherper 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.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION