Programmering

Vanlige uttrykk i Java, del 1: Mønstermatching og Mønster-klassen

Java's karakter og diverse strengklasser tilbyr støtte på lavt nivå for mønstermatching, men den støtten fører vanligvis til kompleks kode. For enklere og mer effektiv koding tilbyr Java Regex API. Denne veiledningen i to deler hjelper deg å komme i gang med vanlige uttrykk og Regex API. Først skal vi pakke ut de tre kraftige klassene som bor i java.util.regex pakken, så utforsker vi Mønster klasse og dens sofistikerte mønstermatchende konstruksjoner.

last ned Få koden Last ned kildekoden for eksempel applikasjoner i denne opplæringen. Skapt av Jeff Friesen for JavaWorld.

Hva er vanlige uttrykk?

EN vanlig uttrykk, også kjent som en regex eller regexp, er en streng hvis mønster (mal) beskriver et sett med strenger. Mønsteret bestemmer hvilke strenger som hører til settet. Et mønster består av bokstavelige tegn og metategn, som er tegn som har spesiell betydning i stedet for en bokstavelig betydning.

Mønster matching er prosessen med å søke i tekst for å identifisere fyrstikker, eller strenger som samsvarer med et regex-mønster. Java støtter mønstermatching via Regex API. API-en består av tre klasser--Mønster, Matcher, og MønsterSyntakseksepsjon- alt ligger i java.util.regex pakke:

  • Mønster gjenstander, også kjent som mønstre, er samlet regekser.
  • Matcher gjenstander, eller matchere, er motorer som tolker mønstre for å finne fyrstikker i tegnsekvenser (objekter hvis klasser implementerer java.lang.CharSequence grensesnitt og fungerer som tekstkilder).
  • MønsterSyntakseksepsjon objekter beskriver ulovlige regex-mønstre.

Java gir også støtte for mønstermatching via forskjellige metoder i sin java.lang.Streng klasse. For eksempel, boolske kamper (String regex) returnerer sant bare hvis påkallingsstrengen samsvarer nøyaktig regexer regex.

Bekvemmelighetsmetoder

Bak scenen, fyrstikker() og StringAndre regex-orienterte bekvemmelighetsmetoder er implementert i form av Regex API.

RegexDemo

Jeg har opprettet RegexDemo applikasjon for å demonstrere Java's regulære uttrykk og de forskjellige metodene som ligger i Mønster, Matcher, og MønsterSyntakseksepsjon klasser. Her er kildekoden for demoen:

Oppføring 1. Demonstrere regexer

importere java.util.regex.Matcher; importere java.util.regex.Pattern; importere java.util.regex.PatternSyntaxException; public class RegexDemo {public static void main (String [] args) {if (args.length! = 2) {System.err.println ("bruk: java RegexDemo regex input"); komme tilbake; } // Konverter nye linje (\ n) tegnsekvenser til nye linje tegn. args [1] = args [1] .replaceAll ("\ n", "\ n"); prøv {System.out.println ("regex =" + args [0]); System.out.println ("input =" + args [1]); Mønster p = Mønster.kompilere (args [0]); Matcher m = p.matcher (args [1]); mens (m.find ()) System.out.println ("Fant [" + m.gruppe () + "] fra" + m.start () + "og slutter med" + (m.end () - 1)); } fange (PatternSyntaxException pse) {System.err.println ("Dårlig regex:" + pse.getMessage ()); System.err.println ("Beskrivelse:" + pse.getDescription ()); System.err.println ("Indeks:" + pse.getIndex ()); System.err.println ("Feil mønster:" + pse.getPattern ()); }}}

Den første tingen RegexDemos hoved() metoden gjør er å validere kommandolinjen. Dette krever to argumenter: det første argumentet er en regex, og det andre argumentet er inngangstekst som skal matches med regex.

Du vil kanskje spesifisere en ny linje (\ n) tegn som en del av inngangsteksten. Den eneste måten å oppnå dette på er å spesifisere en \ karakter etterfulgt av en n karakter. hoved() konverterer denne tegnsekvensen til Unicode-verdi 10.

Hovedtyngden av RegexDemokoden ligger i prøve-å fange konstruere. De prøve blokker først utganger den spesifiserte regex og inndatetekst og oppretter deretter en Mønster objekt som lagrer den kompilerte regexen. (Regexes er samlet for å forbedre ytelsen under mønstermatching.) En matcher blir hentet fra Mønster objekt og brukes til å søke etter treff gjentatte ganger til ingen gjenstår. De å fange blokk påkaller forskjellige MønsterSyntakseksepsjon metoder for å hente ut nyttig informasjon om unntaket. Denne informasjonen blir deretter sendt ut.

Du trenger ikke å vite mer om kildekodens funksjoner på dette tidspunktet; det vil bli klart når du utforsker API-en i del 2. Du trenger imidlertid å lage liste 1. Ta koden fra oppføring 1, og skriv deretter inn følgende i kommandolinjen for å kompilere RegexDemo:

javac RegexDemo.java

Mønster og dets konstruksjoner

Mønster, den første av tre klasser som består av Regex API, er en samlet representasjon av et regulært uttrykk. MønsterSDK-dokumentasjonen beskriver forskjellige regex-konstruksjoner, men med mindre du allerede er en ivrig regex-bruker, kan du bli forvirret av deler av dokumentasjonen. Hva er kvantifiserere og hva er forskjellen mellom grådig, motvillige, og besittende kvantifiserere? Hva er karakterklasser, grensematchere, tilbake referanser, og innebygde flagguttrykk? Jeg vil svare på disse spørsmålene og mer i de neste avsnittene.

Bokstavelige strenger

Den enkleste regex-konstruksjonen er den bokstavelige strengen. Noen deler av inndatateksten må samsvare med dette konstruksjonsmønsteret for å få et vellykket mønstermatch. Tenk på følgende eksempel:

java RegexDemo eple-applet

Dette eksemplet prøver å finne ut om det er samsvar med eple mønster i applet inngangstekst. Følgende produksjon avslører kampen:

regex = apple input = applet Fant [apple] fra 0 og slutter med 4

Utgangen viser oss regex og input tekst, og indikerer deretter en vellykket kamp eple innenfor applet. I tillegg presenterer den start- og sluttindeksene for den kampen: 0 og 4, henholdsvis. Startindeksen identifiserer den første tekstplasseringen der et mønster samsvarer; sluttindeksen identifiserer den siste tekstplasseringen for kampen.

Anta at vi spesifiserer følgende kommandolinje:

java RegexDemo apple crabapple

Denne gangen får vi følgende kamp med forskjellige start- og sluttindekser:

regex = apple input = crabapple Fant [apple] starter kl. 4 og slutter kl. 8

Det omvendte scenariet, der applet er regex og eple er inngangsteksten, avslører ingen samsvar. Hele regexen må matche, og i dette tilfellet inneholder ikke inngangsteksten a t etter eple.

Metategn

Kraftigere regex-konstruksjoner kombinerer bokstavlige tegn med metategn. For eksempel i a.b, perioden metakarakter (.) representerer ethvert tegn som vises mellom en og b. Tenk på følgende eksempel:

java RegexDemo .ox "Den raske brunrevenen hopper over den late oksen."

Dette eksemplet spesifiserer .okse som regex og Den raske brunrevenen hopper over den late oksen. som inngangsteksten. RegexDemo søker i teksten etter treff som begynner med et hvilket som helst tegn og slutter med okse. Den gir følgende utgang:

regex = .ox input = Den raske brunrevenen hopper over lat oksen. Fant [rev] som begynner klokken 16 og slutter ved klokken 18 Fant [okse] starter ved 39 og slutter ved 41

Resultatet avslører to treff: rev og okse (med den ledende romkarakteren). De . metacharacter samsvarer med f i den første kampen og mellomromstegnet i den andre kampen.

Hva skjer når vi bytter ut .okse med perioden metakarakter? Det vil si hvilken utgang som er resultatet av å spesifisere følgende kommandolinje:

java RegexDemo. "Den kjappe brunrevenen hopper over den late oksen."

Fordi metakarakteren fra perioden samsvarer med et hvilket som helst tegn, RegexDemo sender ut et treff for hvert tegn (inkludert avslutningsperioden) i inngangsteksten:

regex =. input = Den raske brunrevenen hopper over lat oksen. Fant [T] starter ved 0 og slutter ved 0 Fant [h] starter ved 1 og slutter ved 1 Fant [e] starter ved 2 og slutter ved 2 Fant [] starter ved 3 og slutter ved 3 Fant [q] starter ved 4 og slutter ved 4 Fant [u] starter ved 5 og slutter med 5 Fant [i] starter ved 6 og slutter ved 6 Fant [c] starter ved 7 og slutter ved 7 Fant [k] starter ved 8 og slutter ved 8 Found [ ] starter ved 9 og slutter ved 9 Fant [b] starter ved 10 og slutter ved 10 Fant [r] begynner ved 11 og slutter ved 11 Fant [o] starter kl 12 og slutter ved 12 Fant [w] begynner kl 13 og slutter kl 13 Funnet [n] begynner kl 14 og slutter kl 14 Funnet [] begynner kl 15 og slutter kl 15 Funnet [f] begynner kl 16 og slutter kl 16 Funnet [o] starter kl 17 og slutter kl 17 Funnet [x] starter kl 18 og slutter kl 18 Fant [] begynner kl 19 og slutter kl 19 Fant [j] begynner kl 20 og slutter kl 20 Fant [u] starter kl 21 og slutter kl 21 Fant [m] begynner kl 22 og slutter kl 22 Fant [p] starter ved 23 og slutter med 23 Fant [s] st arting at 24 and ending at 24 Found [] starting at 25 and ending at 25 Found [o] starting at 26 and ending at 26 Found [v] starting at 27 and ending at 27 Found [e] starting at 28 and ending at 28 Fant [r] starter ved 29 og slutter ved 29 Fant [] begynner ved 30 og slutter ved 30 Fant [t] starter ved 31 og slutter ved 31 Fant [h] starter ved 32 og slutter ved 32 Fant [e] starter ved 33 og slutter ved 33 Fant [] starter ved 34 og slutter ved 34 Fant [l] starter ved 35 og slutter ved 35 Fant [a] starter ved 36 og slutter ved 36 Fant [z] starter ved 37 og slutter ved 37 Fant [y ] begynner ved 38 og slutter ved 38 Fant [] starter ved 39 og slutter ved 39 Fant [o] starter ved 40 og slutter ved 40 Fant [x] starter ved 41 og slutter ved 41 Fant [.] begynner ved 42 og slutter ved 42

Sitere metategn

For å spesifisere . eller en hvilken som helst metakarakter som en bokstavelig karakter i en regex-konstruksjon, sitat metakarakteren på en av følgende måter:

  • Gå foran metategnet med en tilbakeslagstegn.
  • Plasser metategnet mellom \ Q og \ E (f.eks. \ Q. \ E).

Husk å doble hvert tilbakeslagstegn (som i \\. eller \ Q. \ E.) som vises i en streng bokstavelig som Streng regex = "\.";. Ikke doble tilbakeslagstegnet når det vises som en del av et kommandolinjeargument.

Karakterklasser

Noen ganger må vi begrense tegn som vil gi samsvar til et bestemt tegnsett. For eksempel kan vi søke i tekst etter vokaler en, e, Jeg, o, og u, der enhver forekomst av vokal indikerer en samsvar. EN karakterklasse identifiserer et sett med tegn mellom metategn med firkantet parentes ([ ]), og hjelper oss med å utføre denne oppgaven. Mønster støtter enkel, negasjon, rekkevidde, forening, kryss og subtraksjon karakterklasser. Vi ser på alle disse nedenfor.

Enkel karakterklasse

De enkel karakterklasse består av tegn plassert side om side og samsvarer bare med tegnene. For eksempel, [abc] samsvarer med tegn en, b, og c.

Tenk på følgende eksempel:

java RegexDemo [csw] hule

Dette eksemplet samsvarer bare c med sin motpart i hule, som vist i følgende utgang:

regex = [csw] input = hule Fant [c] starter ved 0 og slutter ved 0

Negasjon karakter klasse

De negasjon karakter klasse begynner med ^ metakarakter og samsvarer bare med tegnene som ikke er i den klassen. For eksempel, [^ abc] samsvarer med alle tegn unntatt en, b, og c.

Tenk på dette eksemplet:

java RegexDemo "[^ csw]" hule

Merk at de dobbelte anførselstegnene er nødvendige på Windows-plattformen, hvis skall behandler ^ karakter som en fluktfigur.

Dette eksemplet stemmer overens en, v, og e med sine kolleger i hule, som vist her:

regex = [^ csw] input = hule Fant [a] starter ved 1 og slutter ved 1 Fant [v] starter ved 2 og slutter ved 2 Fant [e] starter ved 3 og slutter ved 3

Range karakterklasse

De rekkevidde karakterklasse består av to tegn adskilt av en bindestrek-metategn (-). Alle tegn som begynner med tegnet til venstre for bindestreket og slutter med tegnet til høyre for bindestreket, tilhører området. For eksempel, [a-z] samsvarer med alle små bokstaver. Det tilsvarer å spesifisere [abcdefghijklmnopqrstuvwxyz].

Tenk på følgende eksempel:

java RegexDemo [a-c] klovn

Dette eksemplet samsvarer bare c med sin motpart i klovn, som vist:

regex = [a-c] input = clown Fant [c] starter ved 0 og slutter ved 0

Slå sammen flere områder

Du kan slå sammen flere områder i samme karakterklasse ved å plassere dem side om side. For eksempel, [a-zA-Z] samsvarer med alfabetiske små og små bokstaver.

Union karakter klasse

De fagforeningskarakterklasse består av flere nestede karakterklasser og samsvarer med alle tegnene som tilhører den resulterende foreningen. For eksempel, [a-d [m-p]] samsvarer med tegn en gjennom d og m gjennom s.

Tenk på følgende eksempel:

java RegexDemo [ab [c-e]] abcdef

Dette eksemplet stemmer overens en, b, c, d, og e med sine kolleger i A B C D E F:

regex = [ab [ce]] input = abcdef Fant [a] starter ved 0 og slutter ved 0 Fant [b] starter ved 1 og slutter ved 1 Fant [c] starter ved 2 og slutter ved 2 Fant [d] starter ved 3 og slutter ved 3 Fant [e] fra 4 og slutter ved 4

Krysskarakterklasse

De kryss karakterklasse består av tegn som er felles for alle nestede klasser og samsvarer med bare vanlige tegn. For eksempel, [a-z && [d-f]] samsvarer med tegn d, e, og f.

Tenk på følgende eksempel:

java RegexDemo "[aeiouy && [y]]" fest

Merk at doble anførselstegn er nødvendige på Windows-plattformen, hvis skall behandler & karakter som kommandoseparator.

Dette eksemplet samsvarer bare y med sin motpart i parti:

regex = [aeiouy && [y]] input = party Fant [y] starter kl. 4 og slutter kl. 4
$config[zx-auto] not found$config[zx-overlay] not found