&Anders.Lund; &Anders.Lund.mail;
Marek
Laane

    bald@starman.ee

Tõlge eesti keelde

# Regulaaravaldised

    See lisa tutvustab lühidalt, kuid loodetavasti piisavalt
    üksikasjalikult regulaaravaldiste
    maailma. Siin on dokumenteeritud regulaaravaldisi nii, nagu
    neid kasutab &kate;, mis ei ole päris sama ei sellega, kuidas
    käsitleb regulaaravaldisi Perl, ega sellega, mida arvab nendest
    näiteks grep.

## Sissejuhatus

Regulaaravaldised võimaldavad meil kirjeldada mingi tekstistringi võimalikku sisu moel, millest arvuti aru saab, nii et meil on võimalik otsida tekstist selle stringi võimalikke vasteid ning selleks suutlike rakenduste korral ka vajadusel leitud millegagi asendada.

Näide: oletame, et soovid leida tekstist lõigud, mille alguses seisaks nimi Henrik või Pernilla ja millele järgneks verbi ütlema mingi vorm.

Tavalise otsingu puhul alustaksid ilmselt esimese nime Henrik otsimisega, millele järgneks ütle, näiteks `Henrik ütle`, ning sobivuste otsimisel tuleks kõrvale heita need, mis ei seisa lõigu alguses, samuti need, kus ütle vasteks ei ole mitte ütles või ütleb, mis sind huvitavad, vaid midagi muud. Ja siis tuleb seda kõike korrata järgmise nimega...

Regulaaravaldist kasutades saab selle ülesande sooritada üheainsa otsinguga ning märksa täpsemalt.

Selleks määravad regulaaravaldiswed üldistavad, kuid ometi üksikasjalikud reeglid sobiva stringi leidmiseks. Meie näiteks võiks seda sõnades väljendada nii: Rida, mille alguses seisab kas Henrik või Pernilla (millele võib järgneda kuni neli tühi- või tabeldusmärki), millele järgneb tühimärk, millele järgneb ütle, millele järgneb kas s või b. Ja regulaaravaldisena näeks see välja nii:

`^[ \t]{0,4}(Henrik|Pernilla) ütle(s|b)`

Toodud näites on kasutatud kõiki nelja moodsas regulaaravaldises kasutatavat põhimõtet, nimelt:

- Mustrid

- Eeldused

- Kvantorid

- Tagasiviited

Avaldist alustav katus (`^`) on eeldus, olles õige ainult juhul, kui järgnev string asub tõesti rea alguses.

Stringid `[ \t]` ja `(Henrik|Pernilla) ütle(s|b)` on mustrid. Esimene on märgiklass, millele vastab kas tühik või (horisontaalne) tabeldusmärk, teine muster sisaldab kõigepealt alammustrit, millele vastab kas `Henrik` või `Pernilla`, seejärel osa, millele vastab täpselt string `ütle`, ning lõpuks alammustrit, millele vastab kas `s` või `b`.

String `{0,4}` on kvantor, mis annab teada kuskil 0 kuni 4 kaugusel eelmisest.

Et regulaaravaldise rakendus, mis toetab tagasiviiteid, salvestab kogu stringi sobiva osa, samuti sulgudesse võetud alammustrid, võime nii kogu sobivust (regulaaravaldise otsingul redaktoris avatud tekstidokumendis märgitakse see enamasti valituks) või leitud nime või tegusõna viimase osa, mille kohta viited käivad, uuesti tarvitada.

Ühtekokku leiab avaldis sobivused sealt ja ainult sealt, kus me seda soovime.

Järgnevates osades kirjeldame põhjalikumalt, kuidas luua ja kasutada mustreid, märgiklasse, eeldusi, kvantoreid ja tagasiviiteid ning viimases osas pakume ka mõned tulusad näited.

## Mustrid

Mustrid koosnevad literaalsetest stringidest ja märgiklassides. Mustrid võivad sisaldada alammustreid, mis kujutavad endast sulgudes antud mustrit.

### Paomärgid

Nii mustrites kui märgiklassides on mõnel märgil eritähendus. Neile literaalse sobivuse leidmiseks tuleb nad spetsiaalselt märkida ehk pakku päästa, et regulaaravaldise rakendus aru saaks, et neid märke tuleb käsitleda mitte metamärkide, vaid just nende märkidena, mida nad inimeste arvates peaksidki tähendama.

Seda tehakse märgi ette längkriipsu asetades (`\`).

Regulaaravaldise rakendus ignoreerib paomärki, mis seisab sellise märgi ees, millel antud kontekstis ei ole eritähendust: näiteks längkriips võib j ees (`\j`) olla või mitte olla, mingit vahet ei ole. Kui sa ei tea täpselt, kas märgil võib olla eritähendus või mitte, on paomärgi kasutamine igati mõttekas.

Paomärki tasub kasutada mõistagi ka längkriipsu enda korral: kui just seda on vaja otsida-asendada, siis tulebki kirjutada `\\`.

### Märgiklassid ja lühendid

Märgiklass on avaldis, mis sobib teatud määratud märgikogumiga. Regulaaravaldiste puhul defineeritakse märgiklassid klassi kuuluvaid märke nurksulgudesse `[]` asetades või mõnda allpool kirjeldatud lühendatud klassi kasutades.

Lihtsad märgiklassid sisaldavad vaid ühe või enam literaalse märgi, näiteks `[abc]` (sobivad tähed a, b või c) või `[0123456789]` (sobib iga number).

Kuna tähtedel ja numbritel on loogiline järjekord, võib neid vahemikke määrates ka lühendada: `[a-c]` on sama, mis `[abc]` ja `[0-9]` on sama, mis `[0123456789]`. Täiesti võimalik on ka selliseid konstruktsioone kombineerida, näiteks `[a-fynot1-38]` (selle vastab mõistagi kas a,b,c,d, e,f,y,n,o,t, 1,2,3 või 8).

Et suur- ja väiketähti käsitletakse erinevatena, siis tuleb tõstutundetu märgiklassi loomiseks, mis leiaks näiteks a ja b, kindlasti kirjutada `[aAbB]`.

Mõistagi on võimalik luua ka negatiivseid märgiklasse, kus sobib kõik, välja arvatud. Selleks tuleb klassi algusse asetada katus (`^`):

`[^abc]` tähendab, et sobib iga märk, välja arvatud a, b või c.

Lisaks literaalsetele sümbolitele on elu ja töö hõlbustamiseks defineeritud ka teatud valik lühendeid:

`\a`

  Sobib ASCII signaalimärk (BEL, 0x07).

`\f`

  Sobib ASCII lehevahetusmärk (FF, 0x0C).

`\n`

  Sobib ASCII reavahetusmärk (LF, 0x0A, Unixis uus rida).

`\r`

  Sobib ASCII kelgu tagastamise märk (CR, 0x0D).

`\t`

  Sobib ASCII horisontaalne tabeldusmärk (HT, 0x09).

`\v`

  Sobib ASCII vertikaalne tabeldusmärk (VT, 0x0B).

`\xhhhh`

  Sobib Unicode märk, mis vastab kuueteistkümnendnumbrile hhhh (vahemikus 0x0000 ja 0xFFFF). \0ooo (&ie; \null ooo) sobib ASCII/Latin-1 sümboliga, mis vastab kaheksandnumbrile 000 (vahemikus 0 ja 0377).

`.` (punkt)

  Sobib suvaline märk (kaasa arvatud reavahetusmärk).

`\d`

  Sobib arv. Sama, mis `[0-9]`.

`\D`

  Sobib mitte-arv. Sama , mis `[^0-9]` või `[^\d]`.

`\s`

  Sobib tühimärk. Praktiliselt sama, mis `[ \t\n\r]`.

`\S`

  Sobib mitte-tühimärk. Praktiliselt sama, mis `[^ \t\r\n]`, ja sama, mis `[^\s]`

`\w`

  Sobib iga täheline märk - antud juhul siis suvaline täht või number. Arvesta, et alakriips `_` nende hulka ei käi erinevalt Perli regulaaravaldistest. Sama, mis `[a-zA-Z0-9]`.

`\W`

  Sobib iga mittetäheline märk - seega kõik, mis ei ole täht ega number. Sama, mis `[^a-zA-Z0-9]` või `[^\w]`.

Lühendatud klasse võib asetada tavalise klassi sisse, näiteks tähelise märgi, tühiku või punkti leidmiseks võib kirjutada `[\w \.]`.

POSIXi klasside notatsioon `[:<klassi nimi>:]` ei ole veel toetatud.

#### Eritähendusega märgid märgiklassides

Järgmistel märkidel on eritähendus, kui nad esinevad märgiklassi konstruktsiooni [] sees ja nad tuleb varustada paomärgiga, et neid võetaks literaalselt:

`]`

  Märgiklassi lõpp. Vajalik on paomärk, kui see pole klassi kõige esimene märk (millele võib järgneda paomärgita katus).

`^` (katus)

  Märgib negatiivset klassi, kui on esimene märk. Kui peab sobima literaalselt, on vajalik paomärk, kui on klassi esimene märk.

`-` (kriips)

  Märgib loogilist vahemikku. Märgiklassis vajab alati paomärki.

`\` (längkriips)

  Paomärk. Vajab alati paomärki.

### Alternatiivid: sobib üks valikust

Kui soovid, et leitaks üks mitme alternatiivse mustri seast, võib alternatiivid eraldada vertikaalse kriipsuga `|`.

Näiteks selleks, et leida kas John või Harry, tuleks kirjutada `John|Harry`.

### Alammustrid

Alammustrid on sulgudesse võetud mustrid, mida saab regulaaravaldistes mitmeti kasutada.

#### Alternatiivide määramine

Alammustriga saab grupeerida alternatiivide valiku mustris. Alternatiivid tuleb eraldada püstkriipsuga |.

Et sobiks näiteks kas või üks sõnadest int, float or double, saab kasutada mustrit `int|float|double`. Kui soovid leida aga neist ühe vaid juhul, kui sellele järgneb üks või enam tühimärki ja siis veel mingid tähed, anna alternatiivid alammustrina: `(int|float|double)\s+\w+`.

#### Sobiva teksti haaramine (tagasiviited)

Kui soovid kasutada tagasiviidet, tarvita alammustrit, mis jätab meelde mustri soovitud osa.

Kui näiteks soovid leida ühe ja sama sõna kaks esinemist, mida eraldab koma ja võib-olla mõned tühimärgid, võid kirjutada `(\w+),\s*\1`. Alammuster `\w+` leiab täheliste märkide kogumi ning kogu avaldis sobib siis, kui sellele järgneb koma, 0 või enam tühimärki ja siis uuesti samasugune täheliste märkide kogum. (String `\1` viitab esimesele sulgudes alammustrile.)

#### Ettevaatavad eeldused

Ettevaatav eeldus on alammuster, mida alustab kas `?=` või `?!`.

Kui näiteks sobima peab literaalne string Bill, aga ainult juhul, kui sellele ei järgne Gates, võib kasutada sellist avaldist: `Bill(?! Gates)`. See leiab nii väljendid Bill Clinton kui ka Billy the Kid, aga ingoneerib muid sobivusi.

Eelduseks kasutatud alammustreid ei haarata.

Vaata ka osa Eeldused

### Eritähendusega märgid mustrites

Järgmistel märkidel on eritähendus, kui nad esinevad mustris, ning need tuleb varustada paomärgiga, kui neid peab võtma literaalselt:

`\` (längkriips)

  Paomärk.

`^` (katus)

  Eeldab stringi algust.

`$`

  Eeldab stringi lõppu.

`()` (vasak- ja parempoolne sulg)

  Märgib alammustreid.

`{}` (vasak- ja parempoolne looksulg)

  Märgib numbrilisi kvantoreid.

`[]` (vasak- ja parempoolne nurksulg)

  Märgib märgiklasse.

`|` (püstkriips)

  Loogiline VÕI. Eraldab alternatiive.

`+` (plussmärk)

  Kvantor 1 või enam.

`*` (tärn)

  Kvantor 0 või enam.

`?` (küsimärk)

  Lisamärk, mida võib tõlgendada kvantorina 0 või 1.

## Kvantorid

Kvantorid lasevad regulaaravaldisel leida määratud arvu või arvuvahemiku märke, märgiklasse või alammustreid.

Kvantorid antakse looksulgudes (`{` ja `}`) ning nad esinevad üldistatult kujul `{[minimaalselt-esinemisi][,[maksimaalselt-esinemisi]]}`

Kasutamist selgitab kõige paremini näide:

`{1}`

  Täpselt 1 esinemine.

`{0,1}`

  Null või 1 esinemine.

`{,1}`

  Sama, aga üks märk vähem kirjutada:-)

`{5,10}`

  Vähemalt 5, aga maksimaalselt 10 esinemist.

`{5,}`

  Vähemalt viis esinemist, maksimum puudub.

Lisaks saab kasutada mõningaid lühendeid:

`*` (tärn)

  sama, mis `{0,}`, leiab suvalise arvu esnemisi.

`+` (plussmärk)

  sama, mis `{1,}`, vähemalt 1 esinemine.

`?` (küsimärk)

  sama, mis `{0,1}`, null või 1 esinemine.

### Ahnus

Kui kasutada kvantoreid ilma maksimumi määramata, otsib regulaaravaldis vaikimisi otsitavat stringi nii palju, kui vähegi võimalik, mida nimetatakse sageli ahneks käitumiseks.

Tänapäevased regulaaravaldiste rakendused pakuvad vahendeid ahnuse väljalülitamiseks, kuigi graafilises keskkonnas on jäänud liidese ülesandeks pakkuda sellist võimalust või mitte. Nii võib näiteks regulaaravaldise võimalusega otsingudialoogis olla märkekast Minimaalne sobivus, samuti võib see märku anda, kas ahnus on vaikimisi sisse lülitatud või mitte.

### Näited

Mõned näited kvantorite kasutamise kohta.

`^\d{4,5}\s`

  Sobivad arvud väljendites 1234 läheb ja 12345 nüüd, aga mitte väljendites 567 üksteist või 223459 kuskil.

`\s+`

  Sobib üks või enam tühimärki.

`(bla){1,}`

  Sobivad kõik väljendid blablabla ja bla väljendites blaster või kõbla.

`/?>`

  Sobib /> väljendis <closeditem/>, samuti > väljendis <openitem>.

## Eeldused

Eeldused võimaldavad leida regulaaravaldise sobivuse ainult teatud määratud tingimustel.

Eeldus ei otsi õigupoolest sobivat märki, vaid uurib lähikonnast võimalikke sobivusi, enne kui midagi omaks võtta. Näiteks sõnapiirde eeldus ei püüa leida mitte antud positsioonis mittetähelist märki, vaid kontrollib, et seal ei oleks tähelist märki. See tähendab, et eeldus sobbi, kui tegemist ei ole märgiga, &ie; tegemist on otsitava stringi alguse ja lõpuga.

Mõned eeldused ei otsi õigupoolest sobivat mustrit, vaid osa stringi sobivust, mis ei ole terve avaldise sobivuse tulemus.

Siin dokumenteeritud regulaaravaldised toetavad järgmisi eeldusi:

`^` (katus: stringi algus)

  Sobib otsitava stringi algus.

  Avaldisega `^Peeter` sobib Peeter stringis Peeter, he!, aga mitte stringis Hei, Peeter!.

`$` (stringi lõpp)

  Sobib otsitava stringi lõpp.

  Avaldisega `ju\?$` sobib stringi Sa ei teinud seda, eks ju?, aga mitte stringi Sa ei teinud seda, eks? lõpp.

`\b` (sõnapiire)

  Sobib, kui ühel pool on täheline märk ja teisel pool mittetäheline märk.

  Sellest on abi konkreetsete sõnade leidmisel, eriti kui näiteks määrata kogu sõna sobivus. Avaldisega `\bjuures\b` sobib eraldiseisva sõnaga juures näiteks lauses Ta seisis akna juures vaikides, aga mitte näiteks sõnas juurestik.

`\B` (mitte-sõnapiire)

  Sobib kõikjal, kus \b ei sobi.

  See tähendab, et sobivus asub sõna sees: avaldisega `\Bjuures\B` sobib alusjuurestik, aga mitte juurestik või sealjuures.

`(?=MUSTER)` (positiivne ettevaade)

  Ettevaatav eeldus uurib sobivuse leidmiseks selle järgnevat stringi. Positiivne ettevaade ei näita sobivust, kui võimalikule sobivusele järgnev tekst ei vasta eelduse MUSTRILE, vaid tekstile, mis sellega sobib, mida ei kaasata tulemusse.

  Avaldisega `käsi(?=\w)` sobib käsi stringis käsitööline, aga mitte stringis See on meie neljas käsi!.

`(?!MUSTER)` (negatiivne ettevaade)

  Negatiivne ettevaade ei näita sobivust, kui otsitavale stringile järgnev osa ei vasta MUSTRILE.

  Avaldisega `const \w+\b(?!\s*&)` sobib const char in the string const char* foo, aga mitte const QString stringis const QString& bar, sest & sobib negatiivse ettevaatava eelduse mustriga.