CodeGym /Java-blogg /Tilfeldig /Vanlige uttrykk i Java
John Squirrels
Nivå
San Francisco

Vanlige uttrykk i Java

Publisert i gruppen
Regelmessige uttrykk er et tema som programmerere, selv erfarne, ofte utsetter til senere. Men før eller siden må de fleste Java-utviklere behandle tekstinformasjon. Oftest betyr dette søk og redigering av tekst. Uten regulære uttrykk er effektiv og kompakt tekstbehandlingskode rett og slett utenkelig. Så slutt å utsette, la oss takle regulære uttrykk akkurat nå. Det er ikke så vanskelig. Regelmessige uttrykk i Java - 1

Hva er et regulært uttrykk (regex)?

Faktisk er et regulært uttrykk et mønster for å finne en streng i tekst. I Java er den opprinnelige representasjonen av dette mønsteret alltid en streng, dvs. et objekt i klassen String. Det er imidlertid ikke en hvilken som helst streng som kan kompileres til et regulært uttrykk - bare strenger som samsvarer med reglene for å lage regulære uttrykk. Syntaksen er definert i språkspesifikasjonen. Regulære uttrykk skrives ved hjelp av bokstaver og tall, samt metategn, som er tegn som har spesiell betydning i regulære uttrykkssyntaks. For eksempel:

String regex = "java"; // The pattern is "java";
String regex = "\\d{3}"; // The pattern is three digits;

Lage regulære uttrykk i Java

Å lage et regulært uttrykk i Java innebærer to enkle trinn:
  1. skriv det som en streng som samsvarer med syntaks for regulære uttrykk;
  2. kompiler strengen til et regulært uttrykk;
I et hvilket som helst Java-program begynner vi å jobbe med regulære uttrykk ved å lage et Patternobjekt. For å gjøre dette må vi kalle en av klassens to statiske metoder: compile. Den første metoden tar ett argument - en streng som inneholder det regulære uttrykket, mens den andre tar et ekstra argument som bestemmer innstillingene for mønstersamsvar:

public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
Listen over potensielle verdier for flagsparameteren er definert i Patternklasse og er tilgjengelig for oss som statiske klassevariabler. For eksempel:

Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE); // Pattern-matching will be case insensitive.
I utgangspunktet Patterner klassen en konstruktør for regulære uttrykk. Under panseret compilekaller metoden Patternklassens private konstruktør for å lage en kompilert representasjon. Denne objektopprettingsmekanismen implementeres på denne måten for å lage uforanderlige objekter. Når et regulært uttrykk opprettes, blir syntaksen sjekket. Hvis strengen inneholder feil, PatternSyntaxExceptiongenereres a.

Syntaks for regulære uttrykk

Syntaks for regulære uttrykk er avhengig av <([{\^-=$!|]})?*+.>tegnene, som kan kombineres med bokstaver. Avhengig av deres rolle, kan de deles inn i flere grupper:
1. Metategn for å matche grensene til linjer eller tekst
Metakarakter Beskrivelse
^ begynnelsen av en linje
$ slutten av en linje
\b ordgrense
\B ikke-ord grense
\EN begynnelsen av inngangen
\G slutten av forrige kamp
\Z slutten av inngangen
\z slutten av inngangen
2. Metategn for å matche forhåndsdefinerte tegnklasser
Metakarakter Beskrivelse
\d siffer
\D ikke-sifret
\s blanktegn
\S ikke-mellomrom
\w alfanumerisk tegn eller understrek
\W alle tegn unntatt bokstaver, tall og understrek
. hvilken som helst karakter
3. Metategn for samsvarende kontrolltegn
Metakarakter Beskrivelse
\t tabulatortegn
\n nylinjekarakter
\r vognretur
\f linjefeed-karakter
\u0085 neste linje tegn
\u2028 linjeskiller
\u2029 avsnittsskiller
4. Metategn for karakterklasser
Metakarakter Beskrivelse
[abc] noen av de oppførte tegnene (a, b eller c)
[^abc] andre tegn enn de som er oppført (ikke a, b eller c)
[a-zA-Z] sammenslåtte områder (latinske tegn fra a til å, skiller mellom store og små bokstaver)
[annonse[mp]] forening av tegn (fra a til d og fra m til p)
[az&&[def]] skjæringspunktet mellom tegn (d, e, f)
[az&&[^bc]] subtraksjon av tegn (a, dz)
5. Metategn for å angi antall tegn (kvantifiserere). En kvantifiserer alltid innledes med et tegn eller en tegngruppe.
Metakarakter Beskrivelse
? en eller ingen
* null eller flere ganger
+ en eller flere ganger
{n} n ganger
{n,} n eller flere ganger
{n,m} minst n ganger og ikke mer enn m ganger

Grådige kvantifiserere

En ting du bør vite om kvantifiserere er at de kommer i tre forskjellige varianter: grådige, besittende og motvillige. Du gjør en kvantifier besittende ved å legge til et " +"-tegn etter kvantifisereren. Du gjør det motvillig ved å legge til " ?". For eksempel:

"A.+a" // greedy
"A.++a" // possessive
"A.+?a" // reluctant
La oss prøve å bruke dette mønsteret for å forstå hvordan de forskjellige typene kvantifiserere fungerer. Som standard er kvantifiserere grådige. Det betyr at de ser etter den lengste kampen i strengen. Hvis vi kjører følgende kode:

public static void main(String[] args) {
    String text = "Fred Anna Alexander";
    Pattern pattern = Pattern.compile("A.+a");
    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        System.out.println(text.substring(matcher.start(), matcher.end()));
    }
}
vi får denne utgangen:

Anna Alexa
For det regulære uttrykket " A.+a", utføres mønstertilpasning som følger:
  1. Det første tegnet i det angitte mønsteret er den latinske bokstaven A. Matchersammenligner det med hvert tegn i teksten, fra indeks null. Tegnet Fer på null i teksten vår, så Matcherdet går gjennom tegnene til det samsvarer med mønsteret. I vårt eksempel er dette tegnet funnet på indeks 5.

    Regelmessige uttrykk i Java - 2
  2. Når en match med mønsterets første karakter er funnet, Matcherser du etter en match med det andre tegnet. I vårt tilfelle er det .tegnet " ", som står for et hvilket som helst tegn.

    Regelmessige uttrykk i Java - 3

    Karakteren ner i sjette posisjon. Det kvalifiserer absolutt som en kamp for "hvilken som helst karakter".

  3. Matcherfortsetter for å sjekke neste tegn i mønsteret. I vårt mønster er det inkludert i kvantifikatoren som gjelder for det foregående tegnet: " .+". Fordi antall repetisjoner av "hvilket som helst tegn" i mønsteret vårt er en eller flere ganger, Matchertar gjentatte ganger neste tegn fra strengen og sjekker det mot mønsteret så lenge det samsvarer med "hvilket som helst tegn". I vårt eksempel - til slutten av strengen (fra indeks 7 til indeks 18).

    Vanlige uttrykk i Java - 4

    I utgangspunktet Matchersluker strengen til slutten - det er nettopp dette som menes med "grådig".

  4. Etter at Matcher når slutten av teksten og fullfører sjekken for " A.+"-delen av mønsteret, begynner den å sjekke for resten av mønsteret: a. Det er ikke mer tekst fremover, så sjekken fortsetter med å "gå tilbake", fra det siste tegnet:

    Regelmessige uttrykk i Java - 5
  5. Matcher"husker" antall repetisjoner i " .+"-delen av mønsteret. På dette tidspunktet reduserer den antallet repetisjoner med én og sjekker det større mønsteret mot teksten til en match blir funnet:

    Regelmessige uttrykk i Java - 6

Besittende kvantifiserere

Besittende kvantifiserere er mye som grådige. Forskjellen er at når tekst har blitt fanget til slutten av strengen, er det ingen mønstertilpasning mens "back off". Med andre ord er de tre første stadiene de samme som for grådige kvantifiserere. Etter å ha fanget hele strengen, legger matcheren resten av mønsteret til det den vurderer og sammenligner det med den fangede strengen. I vårt eksempel, ved å bruke det regulære uttrykket " A.++a", finner hovedmetoden ingen treff. Vanlige uttrykk i Java - 7

Motvillige kvantifiserere

  1. For disse kvantifikatorene, som med den grådige varianten, ser koden etter en match basert på det første tegnet i mønsteret:

    Vanlige uttrykk i Java - 8
  2. Deretter ser det etter en match med mønsterets neste tegn (hvilket som helst tegn):

    Regelmessige uttrykk i Java - 9
  3. I motsetning til grådig mønstertilpasning, søkes det korteste treffet i motvillig mønstertilpasning. Dette betyr at etter å ha funnet samsvar med mønsterets andre tegn (en punktum, som tilsvarer tegnet på posisjon 6 i teksten, Matcherkontrollerer om teksten samsvarer med resten av mønsteret — tegnet " a"

    Vanlige uttrykk i Java - 10
  4. Teksten samsvarer ikke med mønsteret (dvs. den inneholder tegnet " n" ved indeks 7), så Matcherdet legges til mer ett "hvilket som helst tegn", fordi kvantifikatoren indikerer en eller flere. Så sammenligner den igjen mønsteret med teksten i posisjon 5 til 8:

    Regelmessige uttrykk i Java - 11
  5. I vårt tilfelle er det funnet et samsvar, men vi har ikke kommet til slutten av teksten ennå. Derfor starter mønstertilpasningen på nytt fra posisjon 9, dvs. mønsterets første tegn letes etter ved hjelp av en lignende algoritme og denne gjentas til slutten av teksten.

    Vanlige uttrykk i Java - 12
Følgelig mainoppnår metoden følgende resultat ved bruk av mønsteret " A.+?a": Anna Alexa Som du kan se fra vårt eksempel, gir forskjellige typer kvantifiserere forskjellige resultater for det samme mønsteret. Så husk dette og velg riktig variant basert på hva du leter etter.

Unngående tegn i regulære uttrykk

Fordi et regulært uttrykk i Java, eller rettere sagt, dets opprinnelige representasjon, er en strengliteral, må vi ta hensyn til Java-regler angående strengliteraler. Spesielt omvendt skråstrek-tegnet " \" i strengbokstaver i Java-kildekoden tolkes som et kontrolltegn som forteller kompilatoren at det neste tegnet er spesielt og må tolkes på en spesiell måte. For eksempel:

String s = "The root directory is \nWindows"; // Move "Windows" to a new line
String s = "The root directory is \u00A7Windows"; // Insert a paragraph symbol before "Windows"
Dette betyr at strengliteraler som beskriver regulære uttrykk og bruker " \"-tegn (dvs. for å indikere metategn) må gjenta skråstrekene for å sikre at Java-bytekode-kompilatoren ikke feiltolker strengen. For eksempel:

String regex = "\\s"; // Pattern for matching a whitespace character
String regex = "\"Windows\"";  // Pattern for matching "Windows"
Doble omvendte skråstreker må også brukes for å unnslippe spesialtegn som vi ønsker å bruke som "normale" tegn. For eksempel:

String regex = "How\\?";  // Pattern for matching "How?"

Metoder i mønsterklassen

Klassen Patternhar andre metoder for å jobbe med regulære uttrykk:
  • String pattern()‒ returnerer det regulære uttrykkets opprinnelige strengrepresentasjon som ble brukt til å lage objektet Pattern:

    
    Pattern pattern = Pattern.compile("abc");
    System.out.println(pattern.pattern()); // "abc"
    
  • static boolean matches(String regex, CharSequence input)– lar deg sjekke det regulære uttrykket som sendes som regulært uttrykk mot teksten som sendes som input. Returnerer:

    sant – hvis teksten samsvarer med mønsteret;
    falsk – hvis den ikke gjør det;

    For eksempel:

    
    System.out.println(Pattern.matches("A.+a","Anna")); // true
    System.out.println(Pattern.matches("A.+a","Fred Anna Alexander")); // false
    
  • int flags()‒ returnerer verdien til mønsterets flagsparametersett da mønsteret ble opprettet eller 0 hvis parameteren ikke ble satt. For eksempel:

    
    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)– deler den beståtte teksten i en Stringmatrise. Parameteren limitangir maksimalt antall treff som søkes etter i teksten:

    • hvis limit > 0limit-1samsvarer;
    • hvis limit < 0‒ alle samsvarer i teksten
    • hvis limit = 0‒ alle samsvarer i teksten, forkastes tomme strenger på slutten av matrisen;

    For eksempel:

    
    public static void main(String[] args) {
        String text = "Fred Anna Alexa";
        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);
        }
    }
    

    Konsoll utgang:

    
    Fred
    Anna Alexa
    ---------
    Fred
    Anna
    Alexa
    

    Nedenfor vil vi vurdere en annen av klassens metoder som brukes til å lage et Matcherobjekt.

Metoder i Matcher-klassen

Forekomster av Matcherklassen er opprettet for å utføre mønstertilpasning. Matcherer "søkemotoren" for regulære uttrykk. For å utføre et søk, må vi gi det to ting: et mønster og en startindeks. For å lage et Matcherobjekt Patterngir klassen følgende metode: рublic Matcher matcher(CharSequence input) Metoden tar en tegnsekvens, som vil bli søkt. Dette er en forekomst av en klasse som implementerer grensesnittet CharSequence. Du kan bestå ikke bare en String, men også en StringBuffer, StringBuilder, Segment, eller CharBuffer. Mønsteret er et Patternobjekt som matchermetoden kalles på. Eksempel på å lage en matcher:

Pattern p = Pattern.compile("a*b"); // Create a compiled representation of the regular expression
Matcher m = p.matcher("aaaaab"); // Create a "search engine" to search the text "aaaaab" for the pattern "a*b"
Nå kan vi bruke "søkemotoren" vår til å søke etter treff, få posisjonen til et treff i teksten og erstatte tekst ved hjelp av klassens metoder. Metoden boolean find()ser etter neste treff i teksten. Vi kan bruke denne metoden og en loop-setning til å analysere en hel tekst som en del av en hendelsesmodell. Vi kan med andre ord utføre nødvendige operasjoner når en hendelse inntreffer, dvs. når vi finner samsvar i teksten. For eksempel kan vi bruke denne klassens int start()og int end()metodene for å bestemme en kamps plassering i teksten. Og vi kan bruke metodene String replaceFirst(String replacement)og String replaceAll(String replacement)for å erstatte treff med verdien av erstatningsparameteren. For eksempel:

public static void main(String[] args) {
    String text = "Fred Anna Alexa";
    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) + " from index "+ start + " through " + (end-1));
    }
    System.out.println(matcher.replaceFirst("Ira"));
    System.out.println(matcher.replaceAll("Mary"));
    System.out.println(text);
}
Produksjon:

Match found: Anna from index 5 through 8
Match found: Alexa from index 10 through 14
Fred Ira Alexa
Fred Mary Mary
Fred Anna Alexa
Eksemplet gjør det klart at metodene replaceFirstog replaceAlloppretter et nytt Stringobjekt - en streng der mønstertreff i den opprinnelige teksten erstattes av teksten som sendes til metoden som et argument. I tillegg replaceFirsterstatter metoden bare det første treffet, men replaceAllmetoden erstatter alle treff i teksten. Den opprinnelige teksten forblir uendret. Klassenes hyppigste regex-operasjoner er innebygd rett inn i Patternklassen . Dette er metoder som , , , og . Men under panseret bruker disse metodene klassene og . Så hvis du vil erstatte tekst eller sammenligne strenger i et program uten å skrive noen ekstra kode, bruk metodene tilMatcherStringsplitmatchesreplaceFirstreplaceAllPatternMatcherStringklasse. Hvis du trenger mer avanserte funksjoner, husk klassene Patternog Matcher.

Konklusjon

I et Java-program er et regulært uttrykk definert av en streng som overholder spesifikke mønstersamsvarsregler. Når du kjører kode, kompilerer Java-maskinen denne strengen til et Patternobjekt og bruker et Matcherobjekt for å finne samsvar i teksten. Som jeg sa i begynnelsen, utsetter folk ofte vanlige uttrykk til senere, og anser dem for å være et vanskelig tema. Men hvis du forstår den grunnleggende syntaksen, metategnene og karakterutslipp, og studerer eksempler på regulære uttrykk, vil du finne at de er mye enklere enn de ser ut ved første øyekast.

Mer lesing:

Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION