Ohjelmointi

Säännölliset lausekkeet Javassa, osa 1: Kuvion sovitus ja Pattern-luokka

Javan hahmot ja valikoidut merkkijonoluokat tarjoavat matalan tason tuen kuvioiden sovittamiselle, mutta tämä tuki johtaa yleensä monimutkaiseen koodiin. Yksinkertaisempaa ja tehokkaampaa koodausta varten Java tarjoaa Regex-sovellusliittymän. Tämä kaksiosainen opetusohjelma auttaa sinua pääsemään alkuun säännöllisten lausekkeiden ja Regex-sovellusliittymän kanssa. Ensin puramme pakkauksessa olevat kolme voimakasta luokkaa java.util.regex paketin, sitten tutkimme Kuvio luokka ja sen hienostuneet kuviosovitusrakenteet.

lataa Hanki koodi Lataa lähdekoodi esimerkiksi sovelluksiin tässä opetusohjelmassa. Luonut Jeff Friesen JavaWorldille.

Mitä ovat säännölliset lausekkeet?

A tavallinen ilme, tunnetaan myös nimellä a regex tai regexp, on merkkijono, jonka kuvio (malli) kuvaa joukon merkkijonoja. Kuvio määrittää, mitkä merkkijonot kuuluvat joukkoon. Kuvio koostuu kirjaimellisista merkeistä ja metahahmot, jotka ovat merkkejä, joilla on erityinen merkitys kirjaimellisen merkityksen sijaan.

Kuvion sovitus on prosessi, jolla etsitään tekstiä tunnistamiseksi Otteluttai merkkijonot, jotka vastaavat regex-mallia. Java tukee mallien sovitusta Regex-sovellusliittymänsä kautta. API koostuu kolmesta luokasta -Kuvio, Matcherja PatternSyntaxException- kaikki sijaitsevat java.util.regex paketti:

  • Kuvio esineitä, tunnetaan myös nimellä kuviot, ovat koottuja regexejä.
  • Matcher esineitä tai ottelijat, ovat moottoreita, jotka tulkitsevat kuvioita osumien löytämiseksi merkkijonot (objektit, joiden luokat toteuttavat java.lang.CharSequence käyttöliittymä ja toimivat tekstilähteinä).
  • PatternSyntaxException esineet kuvaavat laitonta regex-mallia.

Java tarjoaa myös tukea kuvioiden sovittamiseen eri tavoin java.lang.String luokassa. Esimerkiksi, Boolen-ottelut (merkkijono) palauttaa arvon tosi vain jos kutsuva merkkijono täsmää täsmälleen regexon regex.

Kätevyysmenetelmät

Kulissien takana, Ottelut() ja MerkkijonoMuut regex-suuntautuneet mukavuusmenetelmät toteutetaan Regex API: n avulla.

RegexDemo

Olen luonut RegexDemo -sovellus Java: n säännöllisten lausekkeiden ja Kuvio, Matcherja PatternSyntaxException luokat. Tässä on demon lähdekoodi:

Listaus 1. Regexien osoittaminen

tuo java.util.regex.Matcher; tuo java.util.regex.Pattern; tuo java.util.regex.PatternSyntaxException; julkinen luokka RegexDemo {public static void main (Merkkijono [] args) {if (args.pituus! = 2) {System.err.println ("käyttö: java RegexDemo-regex-tulo"); palata; } // Muunna uuden rivin (\ n) merkkijonot uudeksi riviksi. args [1] = args [1] .replaceAll ("\ n", "\ n"); kokeile {System.out.println ("regex =" + args [0]); System.out.println ("input =" + argumentit [1]); Kuvio p = kuvio.koko (args [0]); Matcher m = p.matcher (argumentit [1]); kun (m.find ()) System.out.println ("Löydetty [" + m.ryhmä () + "] alkaen" + m.start () + "ja päättyen" + (m.end () - 1)); } catch (PatternSyntaxException pse) {System.err.println ("Huono regex:" + pse.getMessage ()); System.err.println ("Kuvaus:" + pse.getDescription ()); System.err.println ("Hakemisto:" + pse.getIndex ()); System.err.println ("Virheellinen kuvio:" + pse.getPattern ()); }}}

Ensimmäinen asia RegexDemoon main () menetelmä ei ole validoida komentorivinsä. Tämä vaatii kahta argumenttia: ensimmäinen argumentti on regex, ja toinen argumentti on regexin kanssa sovitettava syöteteksti.

Haluat ehkä määrittää uuden rivin (\ n) -merkki osana syöttötekstiä. Ainoa tapa saavuttaa tämä on määrittää a \ merkki, jota seuraa n merkki. main () muuntaa tämän merkkijonon Unicode-arvoksi 10.

Suurin osa RegexDemokoodi on yrittää-saada kiinni rakentaa. yrittää lohko antaa ensin määritetyn regexin ja syöttötekstin ja luo sitten a Kuvio objekti, joka tallentaa käännetyn regexin. (Regexit laaditaan suorituskyvyn parantamiseksi kuvion sovittamisen aikana.) Matcher puretaan Kuvio objekti ja sitä käytetään toistuvasti etsimään vastaavuuksia, kunnes yhtään ei ole jäljellä. saada kiinni lohko kutsuu erilaisia PatternSyntaxException menetelmiä hyödyllisen tiedon saamiseksi poikkeuksesta. Nämä tiedot lähetetään myöhemmin.

Sinun ei tarvitse tässä vaiheessa tietää enemmän lähdekoodin toiminnasta; se käy selväksi, kun tutkit API: n osaa 2. Sinun on kuitenkin koottava Listing 1. Tartu koodiin luettelosta 1 ja kirjoita sitten seuraava komentorivillesi kääntääksesi RegexDemo:

javac RegexDemo.java

Kuvio ja sen rakenteet

Kuvio, ensimmäinen kolmesta Regex-sovellusliittymän sisältävästä luokasta, on koottu säännöllisen lausekkeen esitys. KuvioSDK: n dokumentaatiossa kuvataan erilaisia ​​regex-rakenteita, mutta ellet ole jo innokas regex-käyttäjä, saatat olla hämmentynyt dokumentaation osista. Mitä ovat kvantifikaattorit ja mitä eroa on ahne, vastahakoinenja omistushaluinen kvantifikaattorit? Mitä ovat hahmoluokat, raja-ottelijat, takaisin viitteetja upotetut lippulausekkeet? Vastaan ​​näihin ja muihin kysymyksiin seuraavissa osioissa.

Kirjaimelliset jouset

Yksinkertaisin regex-rakenne on kirjaimellinen merkkijono. Joitakin syötetekstin osia on vastattava tämän rakenteen mallia saadakseen onnistuneen kuvion vastaavuuden. Harkitse seuraavaa esimerkkiä:

java RegexDemo -omena

Tässä esimerkissä yritetään selvittää, onko omena kuvio sovelma sijoita teksti. Seuraava tulos paljastaa ottelun:

regex = apple input = applet Löytyi [apple] alkaen 0: sta ja päättyen 4: ään

Tulos näyttää meille regex- ja syöttötekstin ja osoittaa sitten onnistuneen ottelun omena sisällä sovelma. Lisäksi se esittää kyseisen ottelun alku- ja loppuhakemistot: 0 ja 4vastaavasti. Aloitusindeksi identifioi ensimmäisen tekstin sijainnin, jossa kuvion täsmäytys tapahtuu; päättyvä hakemisto identifioi ottelun viimeisen tekstin sijainnin.

Oletetaan, että määritämme seuraavan komentorivin:

java RegexDemo Apple Crabapple

Tällä kertaa saamme seuraavan ottelun erilaisilla alku- ja loppuindekseillä:

regex = apple input = crabapple Löydetty [omena] alkaen 4 ja päättyen 8

Käänteinen skenaario, jossa sovelma on regex ja omena on syöttöteksti, ei paljasta yhtään. Koko regexin on vastattava, ja tässä tapauksessa syöteteksti ei sisällä a t jälkeen omena.

Metahahmot

Tehokkaammat regex-rakenteet yhdistävät kirjaimelliset hahmot metahahmoihin. Esimerkiksi a. b, jakson metakuva (.) edustaa mitä tahansa merkkiä, joka esiintyy välissä a ja b. Harkitse seuraavaa esimerkkiä:

java RegexDemo .ox "Nopea ruskea kettu hyppää laiskan härän yli."

Tämä esimerkki määrittelee .härkä kuten regex ja Nopea ruskea kettu hyppää laiskan härän yli. syöttötekstinä. RegexDemo hakee tekstistä vastaavuuksia, jotka alkavat millä tahansa merkillä ja päättyvät härkä. Se tuottaa seuraavan tuotoksen:

regex = .ox input = Nopea ruskea kettu hyppää laiskan härän yli. Löytyi [kettu] alkaen kohdasta 16 ja päättyen arvoon 18 Löydetty [härkä] alkaen kohdasta 39 ja päättyen arvoon 41

Tulos paljastaa kaksi osumaa: kettu ja härkä (johtavan avaruusmerkin kanssa). . metakuva vastaa f ensimmäisessä ottelussa ja välilyönti toisessa ottelussa.

Mitä tapahtuu, kun vaihdamme .härkä kauden metakarakterin kanssa? Eli mikä tulos syntyy seuraavan komentorivin määrittämisestä:

java RegexDemo. "Nopea ruskea kettu hyppää laiskan härän yli."

Koska jakson metakuva vastaa mitä tahansa merkkiä, RegexDemo tuottaa syötteen jokaiselle merkille (mukaan lukien lopetusjakson merkki) syöttötekstissä:

regex =. input = Nopea ruskea kettu hyppää laiskan härän yli. Löytyi [T] alkaen 0 ja päättyen 0 Löydetty [h] alkaen 1 ja päättyen 1 Löydetty [e] alkaen 2 ja päättyen 2 Löydetty [] alkaen 3 ja päättyen 3 Löytynyt [q] alkaen 4 ja päättyy 4 Löydetty [u] alkaen 5 ja päättyen 5 Löydetty [i] alkaen 6 ja päättyen 6 Löydetty [c] alkaen 7 ja päättyen 7 Löydetty [k] alkaen 8 ja päättyen 8 Löytynyt [ ] alkaen 9 ja päättyen 9 Löydetty [b] alkaen 10 ja päättyen 10 Löydetty [r] alkaen 11 ja päättyen 11 Löydetty [o] alkaen 12 ja päättyen 12 Löytynyt [w] alkaen 13 ja päättyen klo 13 Löydetty [n] alkaen 14 ja päättyen 14 Löydetty [] alkaen 15 ja päättyen 15 Löydetty [f] alkaen 16 ja päättyen 16 Löydetty [o] alkaen 17 ja päättyen 17 Löytynyt [x] alkaen klo 18 ja päättyy 18 Löydetty [] alkaen 19 ja päättyen 19 Löytynyt [j] alkaen 20 ja päättyen 20 Löytynyt [u] alkaen 21 ja päättyen 21 Löytynyt [m] alkaen 22 ja päättyen 22 Löydetty [p] alkaen 23 ja päättyen 23 Löydetty [s] st alk. 24 ja päättyy 24 Löydetty [] alkaen 25 ja päättyen 25 Löydetty [o] alkaen 26 ja päättyen 26 Löydetty [v] alkaen 27 ja päättyen 27 Löytynyt [e] alkaen 28 ja päättyen 28 Löytyi [r] alkaen 29 ja päättyen 29 Löydetty [] alkaen 30 ja päättyen 30 Löydetty [t] alkaen 31 ja päättyen 31 Löydetty [h] alkaen 32 ja päättyen 32 Löydetty [e] alkaen 33 ja päättyy 33 Löydetty [] alkaen 34 ja päättyen 34 Löydetty [l] alkaen 35 ja päättyen 35 Löydetty [a] alkaen 36 ja päättyen 36 Löytynyt [z] alkaen 37 ja päättyen 37 Löytynyt [y ] alkaen 38 ja päättyen 38 Löydetty [] alkaen 39 ja päättyen 39 Löytynyt [o] alkaen 40 ja päättyen 40 Löytynyt [x] alkaen 41 ja päättyen 41 Löytynyt [.] alkaen 42 ja päättyen 42

Lainataan metahahmoja

Tarkentaa . tai mitä tahansa metahakua kirjaimellisena merkkinä regex-rakenteessa, lainaus metahakua jollakin seuraavista tavoista:

  • Edeltäkää metakirjoitusta vinoviivalla.
  • Aseta metakuvio väliin \ Q ja \ E (esimerkiksi., \ Q. \ E).

Muista tuplata kukin taaksepäin osoittava merkki (kuten kohdassa \\. tai Q), joka esiintyy merkkijono-kirjaimessa, kuten Merkkijono regex = "\.";. Älä kaksinkertaista vinoviivaa, kun se näkyy osana komentoriviargumenttia.

Hahmoluokat

Meidän on joskus rajoitettava merkit, jotka tuottavat osumia tiettyyn merkistöön. Saatamme esimerkiksi etsiä vokaaleja koskevaa tekstiä a, e, i, oja u, missä vokaalin esiintyminen osoittaa osumaa. A hahmoluokka tunnistaa joukon merkkejä hakasulkeisten metamerkkien välillä ([ ]), auttaa meitä suorittamaan tämän tehtävän. Kuvio tukee yksinkertaisia, negaatio-, alue-, unioni-, leikkaus- ja vähennysluokat. Tarkastelemme kaikkia näitä alla.

Yksinkertainen hahmoluokka

yksinkertainen luokka koostuu vierekkäin sijoitetuista merkeistä ja vastaa vain näitä merkkejä. Esimerkiksi, [abc] vastaa merkkejä a, bja c.

Harkitse seuraavaa esimerkkiä:

java RegexDemo [csw] -luola

Tämä esimerkki vastaa vain c sen vastapuolen kanssa luola, kuten seuraava lähtö osoittaa:

regex = [csw] input = luola Löytyi [c] alkaen 0: sta ja päättyen 0: een

Negation-luokka

negatiivihahmoluokka alkaa ^ metakuva ja vastaa vain niitä merkkejä, jotka eivät kuulu kyseiseen luokkaan. Esimerkiksi, [^ abc] vastaa kaikkia merkkejä paitsi a, bja c.

Harkitse tätä esimerkkiä:

java RegexDemo "[^ csw]" -luola

Huomaa, että kaksoislainausmerkit ovat välttämättömiä Windows-alustalleni, jonka kuori käsittelee ^ hahmo pakohahmona.

Tämä esimerkki vastaa a, vja e kollegoidensa kanssa luola, kuten tässä on esitetty:

regex = [^ csw] input = luola Löytyi [a] alkaen 1 ja päättyen 1 Löydetty [v] alkaen 2 ja päättyen 2 Löydetty [e] alkaen 3 ja päättyen 3

Range-luokka

alueen merkkiluokka koostuu kahdesta merkistä, jotka on erotettu yhdysmerkkimerkillä (-). Kaikki merkit, jotka alkavat yhdysmerkin vasemmalla puolella olevalla merkillä ja päättyvät yhdysmerkin oikealla puolella olevaan merkkiin, kuuluvat alueeseen. Esimerkiksi, [a-z] vastaa kaikkia pieniä aakkosmerkkejä. Se vastaa määrittelyä [abcdefghijklmnopqrstuvwxyz].

Harkitse seuraavaa esimerkkiä:

java RegexDemo [a-c] pelle

Tämä esimerkki vastaa vain c sen vastapuolen kanssa klovni, kuten on esitetty:

regex = [a-c] input = pelle Löydetty [c] alkaen 0: sta ja päättyen 0: een

Yhdistetään useita alueita

Voit yhdistää useita alueita samaan alueen merkkiluokkaan sijoittamalla ne vierekkäin. Esimerkiksi, [a-zA-Z] vastaa kaikkia pieniä ja isoja aakkosmerkkejä.

Unionin luokka

liittohahmoluokka koostuu useista sisäkkäisistä merkkiluokista ja vastaa kaikkia syntyneeseen liittoon kuuluvia merkkejä. Esimerkiksi, [a-d [m-p]] vastaa merkkejä a kautta d ja m kautta s.

Harkitse seuraavaa esimerkkiä:

java RegexDemo [ab [c-e]] abcdef

Tämä esimerkki vastaa a, b, c, dja e kollegoidensa kanssa A B C D E F:

regex = [ab [ce]] input = abcdef Löytyi [a] alkaen 0 ja päättyen 0 Löydetty [b] alkaen 1 ja päättyen 1 Löydetty [c] alkaen 2 ja päättyen 2 Löytynyt [d] alkaen 3 ja päättyy 3 Löytyi [e] alkaen 4 ja päättyen 4

Risteysmerkkiluokka

leikkausmerkkiluokka koostuu merkinnöistä, jotka ovat yhteisiä kaikille sisäkkäisille luokille ja vastaavat vain yhteisiä merkkejä. Esimerkiksi, [a-z && [d-f]] vastaa merkkejä d, eja f.

Harkitse seuraavaa esimerkkiä:

java RegexDemo "[aeiouy && [y]]" -juhlat

Huomaa, että kaksoislainausmerkit ovat välttämättömiä Windows-alustalleni, jonka kuori käsittelee & merkki komentoerottimena.

Tämä esimerkki vastaa vain y sen vastapuolen kanssa juhla:

regex = [aeiouy && [y]] input = puolue Löytyi [y] alkaen 4 ja päättyen 4