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ä, mm. komennoissa [[awk]] ja [[grep]]. Niiden voidaankin sanoa olevan [[putki]]ttamiseen yhdistettynä tärkeimpiä työkaluja, joita komentorivin edistynyt käyttö edellyttää. | ||
== 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 16: | ||
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 58: | ||
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 72: | ||
'''a'''cccca | '''a'''cccca | ||
bba | bba | ||
=====Ehdollinen: <tt>?</tt>===== | =====Ehdollinen: <tt>?</tt>===== | ||
Rivi 118: | Rivi 105: | ||
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. | |||
===== Huomautuksia ===== | ===== Huomautuksia ===== | ||
Rivi 138: | Rivi 123: | ||
'''hu'''aa!! | '''hu'''aa!! | ||
'''hu'''uuurraa!! | '''hu'''uuurraa!! | ||
'''hurr'''urrur!! | '''hurr'''urrur!! | ||
jne. | jne. | ||
Rivi 248: | Rivi 233: | ||
mutta ei | mutta ei | ||
sepe | sepe | ||
====Merkkiluokat: <tt>[]</tt>==== | ====Merkkiluokat: <tt>[]</tt>==== | ||
Rivi 263: | Rivi 249: | ||
[thlTHL]upu | [thlTHL]upu | ||
Hakasulkujen välissä voidaan myös määritellä | Hakasulkujen välissä voidaan myös määritellä 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 276: | Rivi 262: | ||
mutta ei | mutta ei | ||
'''Osasto '''J | '''Osasto '''J | ||
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 281: | ||
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 294: | ||
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 317: | ||
=== 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 360: | Rivi 327: | ||
'''ab'''a | '''ab'''a | ||
'''abb'''bba | '''abb'''bba | ||
==== Esimerkki ==== | ==== Esimerkki ==== | ||
Rivi 390: | Rivi 354: | ||
(... 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 407: | Rivi 371: | ||
'''qmail'''q 3995 3986 0 Jan21 ? 00:00:00 qmail-clean | '''qmail'''q 3995 3986 0 Jan21 ? 00:00:00 qmail-clean | ||
Hattumerkki <tt>^</tt> alussa vastaa jokaisen listausrivin alkua, jota pitää välittömästi seurata merkkijono <tt>qmail</tt>, ja tämän jälkeen voi tulla mikä tahansa | Hattumerkki <tt>^</tt> alussa vastaa jokaisen listausrivin alkua, jota pitää välittömästi seurata merkkijono <tt>qmail</tt>, ja tämän jälkeen voi tulla mikä tahansa merkki (ilmaisu <tt>.</tt>). Grep tulostaa vain lausketta vastaavat rivit, ja tulos on haluttu. | ||
===== 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 380: | ||
$ 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 400: | ||
== 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 441: | ||
*[[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. | ||