Arvutiteaduse instituut
  1. Kursused
  2. 2024/25 kevad
  3. Objektorienteeritud programmeerimine (LTAT.03.003)
EN
Logi sisse

Objektorienteeritud programmeerimine 2024/25 kevad

  • Kodutööd ja praktikumid
  • Loengud
  • Kursuse korraldus
  • IDE juhend
  • Süvendusrühm
  • Silumisest

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õi b;
  • (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 anda compile meetodis. Näiteks CASE_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 ja matches – leiavad sobiva alamsõne (vt meetod1);
  • start – leitud alamsõne alguse indeks (vt meetod2);
  • end – leitud alamsõne lõpu indeks (vt meetod2);
  • appendReplacement – lisab StringBuilder-isse uusi asendatud tekstiga alamsõnesid (vt meetod3);
  • appendTail – lisab StringBuilder-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.
  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused