Muokataan sivua Säännöllinen lauseke
Siirry navigaatioon
Siirry hakuun
Kumoaminen voidaan suorittaa. Varmista alla olevasta vertailusta, että haluat saada aikaan tämän lopputuloksen, ja sen jälkeen julkaise alla näkyvät muutokset.
Nykyinen versio | Oma tekstisi | ||
Rivi 1: | Rivi 1: | ||
'''Säännöllinen lauseke''' (engl. '''regular expression''', '''regexp''') on yksinkertainen merkkijonokieli, joka voi joko ''vastata'' tai ''olla vastaamatta'' jotain toista merkkijonoa. Linux- ja Unix-järjestelmissä säännöllisiä | '''Säännöllinen lauseke''' (engl. '''regular expression''', '''regexp''') on yksinkertainen merkkijonokieli, joka voi joko ''vastata'' tai ''olla vastaamatta'' jotain toista merkkijonoa. Linux- ja Unix-järjestelmissä säännöllisiä lauskkeista on suurta hyötyä [[komentorivi]]ä käytettäessä merkkijonojen etsi/korvaa-toiminnoissa. Niiden voidaankin sanoa olevan [[putki]]ttamiseen yhdistettynä tärkeimpiä työkaluja, joita komentorivin edistynyt käyttö edellyttää. | ||
Tämän säännöllisten lausekkeiden esityksen perusteella lausekkeet ymmärtää, mutta kaikissa yhteyksissä syntaksi ei ole sama. Kolme syntaksityyppiä on yleisesti käytössä: tavallinen ("basic"), laajennettu ("extended") ja [[perl]]-tyyppinen. Ensinmainitussa useammat merkit vastaavat itseään ja esimerkiksi "+" erikoismerkityksessään esitetään "\+". Alla esitetään uudempi laajennettu syntaksi. Varsinkin usealla koneella käytettäviä skriptejä kirjoitettaessa pitää olla huolellinen siinä, mitä lajennoksia käyttää. | |||
Säännöllisiä lausekkeita ei pidä sekoittaa tiedostonimi-jokereihin ("glob"), joilla on osittain sama toiminnallisuus (vrt muoto "*" ja ".*"). | |||
Säännöllisiä lausekkeita ei | |||
== Teoriaa == | == Teoriaa == | ||
Tietojenkäsittelytieteessä puhutaan [[wikipedia:fi:säännöllinen kieli|säännöllisestä kielestä]], joka voidaan tunnistaa [[wikipedia:fi:äärellinen automaatti|äärellisellä automaatilla]]. Säännöllisiä lausekkeita käytetään myös monissa ohjelmointikielissä (mm. Perl, Java, Python, ECMAScript). Mille tahansa [[wikipedia:en:Turing complete|Turing-täydelliselle]] ohjelmointikielelle voidaan kuitenkin aina kirjoittaa säännöllisten lausekkeiden [[wikipedia:fi:Ohjelmointikielen tulkki|tulkki]]. | |||
Säännöllisiä lausekkeita | |||
== Johdatus säännöllisiin lausekkeisiin == | == Johdatus säännöllisiin lausekkeisiin == | ||
Rivi 27: | Rivi 20: | ||
bono | bono | ||
Yleensä (mm. grep ja awk) katsotaan, että kohteen alussa ja lopussa voi olla mielivaltainen määrä ei-vastaavia merkkejä. Tällöin kohde ( | Yleensä (mm. grep ja awk) katsotaan, että kohteen alussa ja lopussa voi olla mielivaltainen määrä ei-vastaavia merkkejä. Tällöin kohde (s.o. näiden komentojen tapauksessa ''rivi'') vastaa lauseketta, jos edes jokin sen ''osa'' vastaa lauseketta. Siis grep ja awk -yhteydessä lauseke | ||
abba | abba | ||
vastaa kohdetta | vastaa kohdetta | ||
Rivi 69: | Rivi 62: | ||
bba | bba | ||
Todettakooon, että selvästi b-merkkien määrä kohteessa voi olla mielivaltainen, joten eri vastaavia kohdemerkkijonoja on olemassa myös ääretön määrä. | |||
=====Vähintään yksi: <tt>+</tt>===== | =====Vähintään yksi: <tt>+</tt>===== | ||
Rivi 83: | Rivi 76: | ||
'''a'''cccca | '''a'''cccca | ||
bba | bba | ||
=====Ehdollinen: <tt>?</tt>===== | =====Ehdollinen: <tt>?</tt>===== | ||
Rivi 118: | Rivi 109: | ||
tarkoittaa ''"korkeintaan m kertaa"''. | tarkoittaa ''"korkeintaan m kertaa"''. | ||
Sivuhuomatuksena todettakoon, että yllä olevan perusteella lyhyemmät operaattorit <tt>*</tt>, <tt>+</tt> ja <tt>?</tt> voitaisiin aina korvata ilmaisuilla <tt>{0,}</tt>, <tt>{1,}</tt> ja <tt>{0,1}</tt> vastaavasti. {m,n}-muoto on kuitenkin uudempi laajennos, joka ei toimi kaikissa ohjelmassa. | |||
===== Huomautuksia ===== | ===== Huomautuksia ===== | ||
Rivi 138: | Rivi 127: | ||
'''hu'''aa!! | '''hu'''aa!! | ||
'''hu'''uuurraa!! | '''hu'''uuurraa!! | ||
'''hurr'''urrur!! | '''hurr'''urrur!! | ||
jne. | jne. | ||
Rivi 248: | Rivi 237: | ||
mutta ei | mutta ei | ||
sepe | sepe | ||
====Merkkiluokat: <tt>[]</tt>==== | ====Merkkiluokat: <tt>[]</tt>==== | ||
Rivi 263: | Rivi 253: | ||
[thlTHL]upu | [thlTHL]upu | ||
Hakasulkujen välissä voidaan myös määritellä [[ | Hakasulkujen välissä voidaan myös määritellä [[locale|LC_COLLATE]] mukaisen aakkoston mukaisia välejä väliviivalla <tt>-</tt>. Tällöin | ||
19[4-9][0-9]|20[0-9][0-9] | 19[4-9][0-9]|20[0-9][0-9] | ||
vastaa kaikkia vuosilukuja välillä 1940-2099. Samoin | vastaa kaikkia vuosilukuja välillä 1940-2099. Samoin | ||
Rivi 277: | Rivi 267: | ||
'''Osasto '''J | '''Osasto '''J | ||
”Osasto b” ja ”Osasto È” saattavat sisältyä, riippuen lokaalista. | |||
Tiettyjä merkkiluokkia on määrätty ennakkoon, esimerkiksi | |||
*[:digit:] vastaa mitä tahansa numeroa | |||
*[:alpha:] vastaa mitä tahansa kirjainta | |||
*[:alnum:] vastaa mitä tahansa kirjainta tai numeroa | |||
Muita tällaisia ovat [:cntrl:], [:lower:], [:upper:], [:space:], [:blank:], [:punct:], [:print:], [:graph:] ja [:xdigit:]. Esimerkiksi <nowiki>[[:upper:]]</nowiki> vastaa C-lokaalilla (LC_CTYPE=C) luokkaa [A-Z]. Merkkiluokkia käytettäessä on huomattava, että käytetty lokaali vaikuttaa ratkaisevasti siihen, mitä merkkejä luokkaan sisältyy. Siksi niitä ei voi käyttää tietoturvatarkistuksiin muuta kuin ennaltamäärätyllä, hyvin ymmärretyllä, lokaalilla. | |||
Jos merkki <tt>-</tt> halutaan sisällyttää hakasulkuilmaisuun, se jätetään viimeiseksi. Esim. | Jos merkki <tt>-</tt> halutaan sisällyttää hakasulkuilmaisuun, se jätetään viimeiseksi. Esim. | ||
Rivi 297: | Rivi 293: | ||
zo | zo | ||
Hakasulkuilmaisusn merkitys voidaan kääntää asettamalla hattu <tt>^</tt> sen ensimmäiseksi merkiksi. Tällöin hakasulkuilmaisu vastaa mitä tahansa hakasuluissa <u>'''ei'''</u> esiintyvää merkkiä kohteessa. Täten lauseke | |||
[^aeiouyåäö]+ | [^aeiouyåäö]+ | ||
vastaa mitä tahansa pelkistä konsonanteista, välimerkeistä ja numeroista koostuvaa kohdetta, kuten | vastaa mitä tahansa pelkistä konsonanteista, välimerkeistä ja numeroista koostuvaa kohdetta, kuten | ||
Rivi 310: | Rivi 306: | ||
Grepin hyväksymissä säännöllisissä lausekkeissa merkin <tt>^</tt> voi sisällyttää hakasulkuilmaukseen laittamalla sen miksi tahansa muuksi merkiksi, kuin hakasulkujen ensimmäinen merkki. Tämä ei pidä välttämättä paikkaansa kuitenkaan kaikilla säännöllisten lausekkeiden toteutuksilla, vaan hattumerkin eteen on mahdollisesti laitettava pako-operaattori <tt>\</tt>. | Grepin hyväksymissä säännöllisissä lausekkeissa merkin <tt>^</tt> voi sisällyttää hakasulkuilmaukseen laittamalla sen miksi tahansa muuksi merkiksi, kuin hakasulkujen ensimmäinen merkki. Tämä ei pidä välttämättä paikkaansa kuitenkaan kaikilla säännöllisten lausekkeiden toteutuksilla, vaan hattumerkin eteen on mahdollisesti laitettava pako-operaattori <tt>\</tt>. | ||
====Pako-operaattori: <tt>\</tt>==== | ====Pako-operaattori: <tt>\</tt>==== | ||
Rivi 350: | Rivi 329: | ||
=== Rivin alku ja loppu: <tt>^</tt> ja <tt>$</tt>=== | === Rivin alku ja loppu: <tt>^</tt> ja <tt>$</tt>=== | ||
On voinut herätä kysymys, kuinka voidaan vastata kohdetta ( | On voinut herätä kysymys, kuinka voidaan vastata kohdetta (s.o. riviä) ''tarkalleen''. Heti alussa selvisi, että esim grepin mielestä kohde (rivi) vastaa lauseketta, jos lauseke esiintyy missä tahansa kohdassa riviä. Jos halutaan, että lauseke vastaa alusta loppuun tarkalleen koko riviä, on otettava käyttöön erikoismerkit <tt>^</tt> ja <tt>$</tt>. Nämä vastaavat kohteessa rivin tai merkkijonon alkua ja loppua kuvaavia "näkymättömiä" merkkejä vastaavasti. Siten | ||
^abba$ | ^abba$ | ||
vastaa vain riviä | vastaa vain riviä | ||
Rivi 390: | Rivi 369: | ||
(... jne ...) | (... jne ...) | ||
Jos haluamme ylläolevasta listasta vain "qmail" -alkuisten [[käyttäjä|käyttäjien]] prosessit, voisimme | Jos haluamme ylläolevasta listasta vain "qmail" -alkuisten [[käyttäjä|käyttäjien]] prosessit, voisimme kirjoittaa | ||
ps -ef | grep qmail | ps -ef | grep qmail | ||
Tämä kuitenkin tulostaa myös kaikki sellaiset prosessit, joiden nimikentässä esiintyy "qmail" – joukossa myös käyttäjän [[root]] prosesseja vastoin alkuperäistä tarkoitusta: | Tämä kuitenkin tulostaa myös kaikki sellaiset prosessit, joiden nimikentässä esiintyy "qmail" – joukossa myös käyttäjän [[root]] prosesseja vastoin alkuperäistä tarkoitusta: | ||
$ ps -ef | grep qmail | $ ps -ef | grep qmail | ||
'''qmail'''s 3986 1 0 Jan21 ? 00:00:00 qmail-send | '''qmail'''s 3986 1 0 Jan21 ? 00:00:00 '''qmail'''-send | ||
'''qmail'''l 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 | '''qmail'''l 3990 3986 0 Jan21 ? 00:00:00 splogger '''qmail''' 2 | ||
root 3993 3986 0 Jan21 ? 00:00:00 '''qmail'''-lspawn | /usr/bin/deliverquota ./Maildir | root 3993 3986 0 Jan21 ? 00:00:00 '''qmail'''-lspawn | /usr/bin/deliverquota ./Maildir | ||
'''qmail'''r 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn | '''qmail'''r 3994 3986 0 Jan21 ? 00:00:00 '''qmail'''-rspawn | ||
'''qmail'''q 3995 3986 0 Jan21 ? 00:00:00 qmail-clean | '''qmail'''q 3995 3986 0 Jan21 ? 00:00:00 '''qmail'''-clean | ||
Ratkaisu qmail -alkuisten käyttäjien prosessien listaamiseen on: | Ratkaisu qmail -alkuisten käyttäjien prosessien listaamiseen on: | ||
Rivi 410: | Rivi 389: | ||
===== Pako komentotulkista ===== | ===== Pako komentotulkista ===== | ||
Jos halutaan antaa jokin monimutkaisempi ilmaisu, on hyvä asettaa säännöllinen lauseke yksinkertaisten heittomerkkien <tt>'</tt> sisään, jotta ne regexp-operaattorit, joillla on jokin erikoismerkitys [[komentotulkki| | Jos halutaan antaa jokin monimutkaisempi ilmaisu, on hyvä asettaa säännöllinen lauseke yksinkertaisten heittomerkkien <tt>'</tt> sisään, jotta ne regexp-operaattorit, joillla on jokin erikoismerkitys [[komentotulkki|komeotulkissa]] eivät aiheuta ongelmia. | ||
$ echo moi | egrep m(o|a)i | $ echo moi | egrep m(o|a)i | ||
-bash: syntax error near unexpected token `(' | -bash: syntax error near unexpected token `(' | ||
Rivi 416: | Rivi 395: | ||
$ echo moi | egrep 'm(o|a)i' | $ echo moi | egrep 'm(o|a)i' | ||
moi | moi | ||
Esimerkissä käytettiin komentoa egrep. Se on oikopolku grepin [[valitsin|valitsimelle]] <tt>-E</tt>, joka ottaa säännöllisten lausekkeiden laajennetun tuen käyttöön. Normaalissa käytössä (pelkkö komento <tt>grep</tt>) operaattorit <tt>? + {} | (</tt> ja <tt>)</tt> eivät ole käytettävissä, paitsi asettamalla niiden eteen pako-operaattori <tt>\</tt>. | |||
Jos ylläolevassa prosessilistausesimerkissä halutaan tulostaa pelkät prosessien [[PID]]-numerot, voidaan käyttää [[awk]]-työkalua seuraavasti: | Jos ylläolevassa prosessilistausesimerkissä halutaan tulostaa pelkät prosessien [[PID]]-numerot, voidaan käyttää [[awk]]-työkalua seuraavasti: | ||
$ ps -ef | awk '/^qmail/ { print $2 }' | $ ps -ef | awk '/^qmail/ { print $2 }' | ||
Rivi 439: | Rivi 415: | ||
== Laajennukset == | == Laajennukset == | ||
Yllä esitetty on hyvä lähtökohta säännöllisiin lausekkeisiin, ja kaikki modernit [[POSIX]]-yhteensopivat toteutukset tukevat mainittuja operaattoreita ja erikoismerkkejä. Monissa ohjelmointikielissä on tehty laajennuksia tähän, mutta esim. [[grep]] ei tue seuraavia. | |||
=== Pakoluokat === | === Pakoluokat === | ||
Jos halutaan kirjoittaa | Jos halutaan kirjoittaa lause, joka jossain kohtaa vastaa mitä tahansa numeromerkkiä, voidaan kirjoittaa hakasulkuilmaus <tt>[0-9]</tt>. Tälläisille yleisesti käytetyille luokille on kuitenkin olemassa laajennuksissa helpompia nimiä. Kutsutaan näitä ''pakoluokiksi''. | ||
{| style="border-style: solid; border-collapse: collapse" border="1" | {| style="border-style: solid; border-collapse: collapse" border="1" | ||
Rivi 480: | Rivi 456: | ||
*[[wikipedia:fi:pinoautomaatti|Pinoautomaatti]] | *[[wikipedia:fi:pinoautomaatti|Pinoautomaatti]] | ||
*[[wikipedia:fi:turingin kone|Turingin kone]] | *[[wikipedia:fi:turingin kone|Turingin kone]] | ||
*[http://www.ohjelmointiputka.net | *[http://www.ohjelmointiputka.net/opas.php?tunnus=phpsl Säännölliset lausekkeet PHP:ssä] -opas Ohjelmointiputkassa | ||
*[http://swtch.com/~rsc/regexp/regexp1.html Regular Expression Matching Can Be Simple And Fast]: Keskustelua säännöllisten lausekkeiden toteutuksesta C-kielellä englanniksi. | *[http://swtch.com/~rsc/regexp/regexp1.html Regular Expression Matching Can Be Simple And Fast]: Keskustelua säännöllisten lausekkeiden toteutuksesta C-kielellä englanniksi. | ||