Arvutiteaduse instituut
  1. Esileht
  2. Automaadid, keeled ja translaatorid
EN
Logi sisse
Tähelepanu! Tehnilise tõrke tõttu on hetkel kättesaadavad vaid 2018.a. ja hilisemad üles laetud failid ja kevadsemestri kursused. Rikke kõrvaldamisega tegeletakse.

Automaadid, keeled ja translaatorid

  • Üldinfo
  • Ajakava
  • Eksami näidised
  • Teemad
    • 1. Soojendus
    • 2. Regulaaravaldised
      • Regex
      • Java API
      • Challenge*
      • Kodutöö
    • 3. Automaadid
    • 4. Avaldise struktuur
    • 5. Grammatikad ja lekser
    • 6. Käsitsi parsimine
    • 7. ANTLRiga töötamine
    • 8. Interpretaator
    • 9. Kompilaator
    • 10. Edasi!
  • Süvendus
  • Bitbucket
  • Moodle
  • Zulip
  • Zoom

Regulaaravaldised

Igal nädalal ilmuvad repositooriumisse uue nädala ülesanded. Selle praktikumi ülesannete saamiseks ära unusta teha git pull (sinine diagonaalne nooleke IDE ülaservas).

Nende küsimuste vastused tuleks kirjutada vastavasse muutujasse failis src/main/java/week2/intro/RegexExercise.java. Sellel on ka vastav test, millega saab ennast kontrollida.

Põhilised operaatorid

RE1: Valik ja täheklassid

Kasutame operaatorit |, et leida kõik read, kus esinevad sõnad "kalad" või "jalad". Selleks võib muidugi kirjutada kalad|jalad ja avaldise ühise teguri "alad" võib viia sulgude taha: (k|j)alad. Valikud üksikute tähtede vahel võib kirjutada kandiliste sulude vahele, näiteks (a|b|c|d|x|y|z) asemel võib kirjutada [abcdxyz] ja isegi [a-dx-z]. Neid nimetatakse täheklassideks (character class). Kasutades kandilistes sulgudes loetletud tähti, greppige kõik read, mis sisaldavad sõnad "kalad" või "jalad".

RE2: Punkt ja eeldefineeritud täheklassid

Eriline sümbolite klass on ., mis sobitub suvalise sümboliga. Proovime nüüd sisendfailist välja greppida sellised read, mis sisaldavad kuskil viietähelist sõne, mille lõpus on tähed "alad", näiteks "jalad" ja "palad". Rohkem eeldefineeritud klasse on regex101 lehel all paremas nurgas reference → common tokens, eriti kasulikud on \w, \d ja \s, aga ka \b, mis sobitub sõnade piiridega. Nende abil võime proovida oma regexit täpsustada, et sobituks ainult viietäheliste sõnadega, s.t. ei sobituks näiteks lausega "Meie mäealad on head alad."

RE3: Epsilon ja küsimärk

Kirjutame nüüd regulaaravaldise, et välja filtreerida read, mis sisaldavad sõna "color" nii inglise kui ka ameerika kirjaviisil. Selleks võib näiteks kirjutada colo(u|)r. Praktikas kasutatakse ε asemel lihtsalt tühjust. See on aga niivõrd tüüpiline konstruktsioon, et selle jaoks on olemas sünonüüm: (E|) asemel võib kirjutada E?. Otsige nüüd üles read, mis sisaldavad sõnad "color" ja "colour", kasutades õiges kohas küsimärki.

Java ja regex101.com jaoks ei ole epsilon eritähendusega. Seega sobitub regex "colo(u|ε)r" sõnadega "colour" ja "coloεr". Epsilon on siin lihtsalt kreeka täht. Teoorias kasutatakse tühja sõne jaoks kas epsiloni või lambdat, aga praktikas on seda harva näha, kus sõnede tähistamiseks kasutatakse jutumärke ja tühja sõne jaoks ei olegi eraldi tähist vaja, vaid kirjutame lihtsalt "".

RE4: Kordamisoperaator Kleene'i tärn

Kordamise operaator * võimaldab leida suvalise arvu tähekordusi, näiteks ja* leiab üles kõik "jaa", "jaaa", ja "jaaaaa", aga kahjuks ka lihtsalt "j" ning "ja". Õigem oleks kirjutada jaaa* (selle jaoks on ka olemas sünonüüm ja{2,}). Kuna me tahame ühte või enamat kordust kaunis sagedasti, siis on selle jaoks eraldi tähis +, nt. a+ on sama, mis aa*. Proovige kirjutada regulaaravaldis, mis leiab üles kõik Rootsipärased "jaha!" moodi ütlused, kus a-de vahele satub üks "h", näiteks "jahaa", "jaaaaha" ja "jaaaahaaaaaaaaaa".

Tehete prioriteet & süntaktiline suhkur

Mitme tehte koos kasutamisel tuleb teada tehete prioriteeti (või kasutada tehete grupeerimiseks sulge). Proovige katsetamise teel jõuda selgusele, kas avaldis b|a* on samaväärne avaldisega (b|a)* või avaldisega b|(a*).

Küllap on teil vaikselt tekkinud arusaam, et paljud lisakonstruktsioonid lisavad ainult mugavust, aga vabalt saaks ka ilma nendeta hakkama, näiteks on aa*, a{1,} ja a+ samaväärsed. Konstruktsioone programmeerimiskeeltes, mis keele võimsust ei muuda, aga teevad kirjutamist mugavamaks, nimetatakse süntaktiliseks suhkruks. Te peaksite oskama näiteks (ab){2,4} välja kirjutada ainult loengus defineeritud operaatorite abil.

Terve rida versus alamsõna matchimine

Teoorias huvitab meid ainult küsimus kas sõne kuulub regulaarse keele hulka või mitte, aga praktikas, kui me näiteks otsime alamsõne ja asendame selle millegi muuga, tekib lisaküsimusi konteksti kohta. On olemas teatud erisümbolid, mis sobituvad ridade ja sõnade algul olevate nähtamatute (tühjade) sümbolitega: ^ on nähtamatu sümbol rea algul, $: nähtamatu sümbol rea lõpul ja \b tähistab nähtamatut sümbolit sõna algul ja lõpul. Paljudel vahenditel on lisaks ka \< ja \> sõna alguse ja lõpu jaoks eraldi.

RE5: Binaarsõned

Proovime leida kõik read, mis ei sisalda muud kui ühtesid ja nulle. Kui lihtsalt kirjutada [01]*, siis saame kogu sisendi tagasi, sest tühi sõne sisaldub igas reas. Siin peab kasutama ^ ja $.

RE6: Eelviimane täht on a

Väljastage kõik read, kus on ainult 'a' ja 'b', aga mille eelviimane täht on "a".

Grupid, tagasiviited, ja operatsioonid regexitega

Lõpuks vaatame ühte operaatorit, mis väga selgelt eristab praktikas kasutatavaid regulaaravaldisi meie formaalsest definitsioonist. Mõnikord kasutatakse sõna "regex", et eristada neid formaalse teooria regulaaravaldistest. Peamine selline operatsioon on tagasiviited (back reference).

RE7: Tagasiviited

Iga sulupaar moodustab nummerdatud grupi (numbered capturing group), millele võib tagasi viidata, näiteks (.)(.)\2\1 sobitub neljatäheliste palindroomidega nagu "ABBA". Proovige ennustada, milliste sisenditega sobituvad ^(ab|ba)(ab|ba)$ ja (ab|ba)\1. Oluline on siin aru saada, mille poolest need kaks avaldist teineteisest erinevad. Kirjutage tagasiviitega regex, mis sobitub neljatäheliste ridadega, mis tükelduvad kaheks võrdeks osaks, näiteks "abab", "aaaa", "haha", jne.

RE8: Replace

Gruppe saab ka kasutada, et leitud sõne asendada teisega, näiteks saab teha järgmise teisenduse: "Eesnimi Perekonnanimi" -> "Perekonnanimi, Eesnimi". (Loengus oli näide vastupidisest suunast.) Proovige see teisendus Javas kirja panna. Proovige kõigepealt, kas oskate lihtsalt ära tunda Eesnimi Perekonnanimi? Asendamisel saab gruppidele viidata dollariga, näiteks $1. Abiks võivad olla ka eeldefineeritud tähetüübid, vt. Pattern klassi doc. Võite ülalolevat teisendust proovida teha ka oma lemmik tekstiredaktoris search&replace funktsionaalsuse abil. MS Wordi jaoks on juhend siin.

RE9: Lazy vs. greedy

Kui teksti otsimiseks ja asendamiseks kasutatakse regulaaravaldisi, siis tekib veel küsimusi, näiteks millega peaks "p.*p" sobituma sisendis "paapapaaaap"? Teoreetiliselt ei ole ju vahet, sest nii terve sõne, kui ka alamsõne "paaap" kuuluvad regulaaravaldise keelde. Teksti asendamisel on aga oluline aru saada "lazy versus greedy" kordamise operaatoritest. Proovige leida võimalikult lihtne regex, millega lauses "This is (not) important (for me)" eemaldada sulud, et tulemus oleks "This is important". Siin on probleem selles, et "\\(.*\\)" sobitub terve alamsõnega "(not) important (for me)", aga tahaks, et sobituks sisemiste sulupaaridega.

Tehniline lisamärkus...

Siin tasub lõpuks mainida, et on üks oluline erinevus loengus esitatud meetodite ja paljude programmeerimiskeelte regex mootorite vahel. Lekseri ja Posixi töövahendid on tekstipõhised ning võtavad alati tekstist pikima sobituse, aga Java on regexipõhine ehk töötleb regexit vasakult paremale, näiteks:

  • "ab".replaceAll("a|ab", "x") ==> "xb"
  • "ab".replaceAll("ab|a", "x") ==> "x"

Seevastu on Posixi käsu sed -E 's/a|ab/x/' <<< "ab" tulemuseks ikkagi "x". Posixi järgi on "a|ab" ja "ab|a" ja "ab?" kõik võrdsed, aga Javas on alternatsiooni järjekord oluline: kui esimene valik sobitub, siis teist enam ei proovita.

  • 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.