Lisamaterjalid 4
Regulaaravaldised
Sõnede töötlemisel võib tekkida vajadus eemaldada kindlaid sümboleid või leida mitu korda esineb mingi sõna. Selleks saab kasutada regulaaravaldisi, millega otsitakse tekstist mustreid. Regulaaravaldistes on paljudele tavalistele sümbolitele, nagu ?
ja +
, antud uus tähendus. Lisaks saab konstrueerida sümbolite hulki kasutades nurksulgi. Väga tihti kasutatakse sümbolit \
, millega koos tähistatakse näiteks numbrite hulka \d
. Java eripäraks on see, et sõne mustriks tegemisel on vaja sisestada ühe längkriipsu asemel kaks ehk \\d
. Edasises tekstis on kasutuses üks längkriips.
Sõnu otsides võib ühte kohta sobida mitu erinevat sümbolit. Sellise sümbolite hulga tähistamiseks kasutatakse regulaaravaldistes nurksulgi:
[abcde]
– 1 täht nurksulgudest loetletud tähtedest;[a-e]
– lühem variant eelmisest näitest. Terve inglise tähestik on[a-z]
või[A-Z]
. Eesti tähestik nii suurte kui ka väikeste tähtedega on[a-zA-ZõüöäÕÜÖÄ]
;[0-9]
– 1 number, mis on vahemikus 0 kuni 9;[^0-9]
– kõik peale numbrite;[a-z[1-4]]
– ühend. Sümbol kuulub hulka[a-z]
või hulka[1-4]
;[a-z&&[abc12]]
– ühisosa. Sümbol on esindatud hulkades[a-z]
ja[abc12]
ehk[abc]
;[a-z&&[^c-z]]
– vahe.[a-z]
, aga mitte[c-z]
ehk[ab]
.
Metamärgid, mis määravad, kui palju mingi sümbol esineb:
*
– esineb ükskõik kui palju kordi;+
– esineb vähemalt 1 kord;?
– esineb 0 või 1 korda;{n}
– esineb n korda;{n,}
– esineb vähemalt n korda;{n,m}
– esineb n kuni m korda.
Regulaaravaldistes tähistavad mõned ladina tähed längkriipsuga kindlaid sümbolite hulki:
\w
– täht, number või alakriips ehk[A-Za-z0-9_]
;\d
– number. Sellega on samaväärne[0-9]
;\s
– tühemik (tühik, tabeldusmärk või sarnane);\n
– uus rida;\b
– käitub sõna piirdena.
Paljudel nendest on suure tähega vastand, näiteks \D
, mis otsib kõike peale numbrite või \S
, mis on tühemiku vastand.
Veel sümboleid:
^
– sõne või rea algus;$
– sõne või rea lõpp;a|b
–a
võib
;(a)
–a
.()
tähistab gruppi, mida saab kasutada lühendatud kujul samas avaldises. Näiteks avaldisele „k(oo)tud ja l\1dud”, kus\1
on(oo)
, vastab kootud ja loodud;.
– kõik peale uut rida alustava sümboli;\
– kui sümbolile on antud tähendus, siis\
eirab seda. Näiteks+
tähendab, et muster esineb vähemalt 1 kord, aga\+
on lihtsalt+
.
Javas regulaaravaldiste loomiseks ja kasutamiseks on olemas pakett java.util.regex
, kus asuvad klassid Pattern
ja Matcher
. Pattern klass esindab regulaaravaldisi ja selle isendeid luuakse sõnest meetodi compile
abil. Sellel klassil on kokku üle kümne meetodi, aga neist tähtsamad on:
pattern
– tagastab regulaaravaldise;matches
– tagastab tõeväärtuse sellest, kas terve argumendiks antud sõne vastab regulaaravaldisele;flags
– tagastab mustrile rakendatud lipud. Neid saab andacompile
meetodis. NäiteksCASE_INSENSITIVE
, mis ignoreerib suurte ja väikeste tähtede erinevusi;split
– tagastab massiivi, mille liikmed on eraldatud regulaaravaldise põhjal.
Regulaaravaldiste tõhusamaks kasutamiseks eksisteerib klass Matcher
. Selle isendeid luuakse klassist Pattern
meetodiga matcher
. See võtab argumendiks sõne, millest otsitakse alamsõnesid. Matcher
klassi olulisemad meetodid on:
find
,lookingAt
jamatches
– leiavad sobiva alamsõne (vt meetod1);start
– leitud alamsõne alguse indeks (vt meetod2);end
– leitud alamsõne lõpu indeks (vt meetod2);appendReplacement
– lisabStringBuilder
-isse uusi asendatud tekstiga alamsõnesid (vt meetod3);appendTail
– lisabStringBuilder
-isse ülejäänud sõne osa, millest ei leitud vastet (vt meetod3);group
– tagastab leitud alamsõne (vt meetod3). Kui argumendiks on antud täisarv, siis tagastatakse regulaaravaldisele vastava grupi leitud alamsõne (vt meetod4);groupCount
– tagastab mitu gruppi on regulaaravaldises (vt meetod4).reset
– lähtestab sobitaja, et see alustaks sõne algusest;pattern
– tagastab regulaaravaldise;usePattern
– asendab kasutatava regulaaravaldise uuega;region
– piirab otsinguala.
Meetod meetod1
võtab argumentideks teksti ja sellest otsitava. See loob sõnest mustri ning sellega sobitaja, mille abil tekstist mustrit otsida. Meetod otsib mustrit kolmel erineval viisil. find()
leiab tekstist järgmise sobiva alamsõne. lookingAt()
otsib teksti algusest alates õiget alamsõne. matches()
vaatab, kas terve sõne sobib mustriga. Tagastatakse massiiv, kus on iga otsingu tulemus tõeväärtusena.
public static boolean[] meetod1(String tekst, String otsitav) { Pattern muster = Pattern.compile(otsitav); Matcher sobitaja = muster.matcher(tekst); boolean kasTekstisOnMuster = sobitaja.find(); boolean kasTekstiAlgusesOnMuster = sobitaja.lookingAt(); boolean kasTekstOnMuster = sobitaja.matches(); return new boolean[]{kasTekstisOnMuster, kasTekstiAlgusesOnMuster, kasTekstOnMuster}; }
Siin on näited, kus alguses on tagastatavas massiivis ainult false
tõeväärtused ja lõpuks on kõik true
:
meetod1("Taevas on sinine ja selge", "kollane");Tagastab:
[false, false, false]
meetod1("Taevas on sinine ja selge", "sinine");
Tagastab: [true, false, false]
meetod1("sinine taevas on ilus", "sinine");
Tagastab: [true, true, false]
meetod1("sinine", "sinine");
Tagastab: [true, true, true]
Meetod meetod2
väljastab tekstist kõik mustrile vastavad alamsõned ja nende indeksite vahemikud. Kõikide vastete saamiseks kasutame meetodi find()
while
-tsüklis. Alamsõne printimiseks sobib group()
ning indeksite vahemiku saamiseks on start()
ja end()
.
public static void meetod2(String tekst, String otsitav) { Pattern muster = Pattern.compile(otsitav); Matcher sobitaja = muster.matcher(tekst); while (sobitaja.find()) { System.out.println("Leitud \"" + sobitaja.group() + "\" indeksite vahemikus " + sobitaja.start() + "-" + sobitaja.end() ); } }
Siin on näited erinevate regulaaravaldistega:
meetod2("Maja on suur ja iga ruum on suur", "suur");
Leiab sõna „suur” esinemised tekstis. Väljund:
Leitud "suur" indeksite vahemikus 8-12 Leitud "suur" indeksite vahemikus 28-32
meetod2("Maja on suur ja iga ruum on suur", "\\b[\\SõüäöÕÜÄÖ]{2}\\b");
Leiab kahetähelisi sõnu. \S
on kõik peale tühemiku. Väljund:
Leitud "on" indeksite vahemikus 5-7 Leitud "ja" indeksite vahemikus 13-15 Leitud "on" indeksite vahemikus 25-27
meetod2("Tema sünnipäev on 15-06-2024, aga minu oma on 53-74-2024", "\\d{2}-\\d{2}-\\d{4}");
Leiab kuupäevi kujul XX-XX-XXXX. Kuna \d
on ükskõik milline number, siis näiteks 53-74-2024
sobib ka. Väljund:
Leitud "15-06-2024" indeksite vahemikus 18-28 Leitud "53-74-2024" indeksite vahemikus 46-56
meetod2("Maa on märg, aga mina pole häiritud", "\\b[Mm][a-zA-ZõüöäÕÜÖÄ]*a\\b");
Leiab kõik sõnad, mis algavad m-tähega ja lõppevad a-tähega. Väljund:
Leitud "Maa" indeksite vahemikus 0-3 Leitud "mina" indeksite vahemikus 17-21
meetod2("Iga lause lõppu käib punkt.", "\\b[\\wõüöäÕÜÖÄ&&[^e0-9]]+\\b");
Leiab kõik e-täheta sõnad. Väljund:
Leitud "Iga" indeksite vahemikus 0-3 Leitud "lõppu" indeksite vahemikus 10-15 Leitud "käib" indeksite vahemikus 16-20 Leitud "punkt" indeksite vahemikus 21-26
meetod2("ta on sama pikk kui ma", "^(ma|sa|ta|me|te)");
Leiab, kas sõne alguses esineb ma, sa, ta, me või te. Väljund:
Leitud "ta" indeksite vahemikus 0-2
Enesekontroll
Kolmas meetod meetod3
asendab tekstis otsitava ning tagastab tulemuse. Mustri loomisel antakse lisaargument Pattern.MULTILINE
. See muudab sümboleid ^
ja $
nii, et kui enne vastasid need ainult sõne algusele ja lõpule, siis nüüd vastavad nad iga rea algusele ja lõpule. Asendatud sõne kokkupanekuks sobib StringBuilder
, millele saab lisada järk-järgult uusi osasid meetodi appendReplacement
abil. Kui rohkem alamsõnesid ei leita, siis appendTail
liidab lõpus muutmata sõne osa lõpptulemusele.
public static String meetod3(String tekst, String otsitav, String asendus) { Pattern muster = Pattern.compile(otsitav, Pattern.MULTILINE); Matcher sobitaja = muster.matcher(tekst); StringBuilder muudetudSõne = new StringBuilder(); while (sobitaja.find()) { sobitaja.appendReplacement(muudetudSõne, asendus); } sobitaja.appendTail(muudetudSõne); return muudetudSõne.toString(); }
Siin on näiteid, milles asendatakse leitud alamsõnesid ning tagastatakse tulemus:
meetod3("Taevas on sinine ja selge", "sinine", "kollane");
Tagastab:
Taevas on kollane ja selge
meetod3("Nägin ilvest metsas", "karu|ilvest|metssiga", "kitse");
Tagastab:
Nägin kitse metsas
meetod3("Rannas elavad grandioossed elukad eks", " ", "\n");
Tagastab:
Rannas elavad grandioossed elukad eks
meetod3("real\nmees\npalus", "^[a-zõüöä]", "s");
Tagastab:
seal sees salus
Viimane meetod meetod4
väljastab leitu kujul „Päev: grupp1. Kuu: grupp2. Aasta: grupp3“, kus grupp1, grupp2 ja grupp3 on alamsõnest leitud grupid. Selleks, et teada mitu gruppi on regulaaravaldises saab kasutada meetodi groupCount()
. Konkreetse grupi tagastamiseks antakse meetodile group
argumendiks vastav täisarv.
public static void meetod4(String tekst, String otsitav) { Matcher sobitaja = Pattern.compile(otsitav).matcher(tekst); int gruppideArv = sobitaja.groupCount(); if (gruppideArv == 3) { while (sobitaja.find()) { String päev = sobitaja.group(1); String kuu = sobitaja.group(2); String aasta = sobitaja.group(3); System.out.println("Päev: " + päev + ". Kuu: " + kuu + ". Aasta: " + aasta + "."); } } }
Siin on kaks erinevat näidet meetodi meetod4
sisenditest ja väljunditest:
String sisend1 = "Tekst ja kuupäev 04.07.2024 ning tekst teisel kujul 55 36. Siis vale kuupäev 34.05.2025 ja veel üks kuupäev 20.06.1995 ning lõpuks vale kuupäev 19.18.2022"; meetod4(sisend1, "([012]\\d|3[01])\\.(0?\\d|1[0-2])\\.(\\d{4})");
See näide leiab kuupäevi kujul XX.XX.XXXX:
Päev: 04. Kuu: 07. Aasta: 2024. Päev: 20. Kuu: 06. Aasta: 1995.
String sisend2 = "Kunagi oli kuupäev 21.11.2024 (neljapäev, november, kaks tuhat kakskümmend neli) ja päev hiljem oli reede (november) ning siis laupäev (külm, tuuline, pilvine)"; meetod4(sisend2, "\\(([a-zA-ZõüöäÕÜÖÄ ]*), ([a-zA-ZõüöäÕÜÖÄ ]*), ([a-zA-ZõüöäÕÜÖÄ ]*)\\)");
Sellele regulaaravaldisele sobivad alamsõned, mis on sulgudes ja sisaldavad kolme sõnade jada eraldatud komadega:
Päev: neljapäev. Kuu: november. Aasta: kaks tuhat kakskümmend neli. Päev: külm. Kuu: tuuline. Aasta: pilvine.