Ero sivun ”Säännöllinen lauseke” versioiden välillä

Siirry navigaatioon Siirry hakuun
1 772 merkkiä lisätty ,  17. helmikuuta 2010
ehostus
(→‎Merkkiluokat: []: LC_COLLATE, [:mikälie:])
(ehostus)
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ä 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ää.
'''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ä esimerkiksi merkkijonojen etsimis- ja korvaustoiminnoissa. 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ää.
Tässä artikkelissa on esitetty johdatus säännöllisiin lausekkeisiin siten, miten komentorivityöklu <tt>[[grep]]</tt> ne ymmärtää ''laajennettussa'' (engl. extended) tilassa. Kaikissa säännöllisten lausekkeiden toteutuksissa syntaksi ei kuitenkaan ole aivan sama. Perusoperaattorit (<tt>*</tt>, <tt>+</tt>, <tt>?</tt>, sulut) ovat kuitenkin ''universaaleja'', eli kaikki toteutukset tukevat niitä.


Säännöllisiä lausekkeita ei pidä sekoittaa tiedostonimi-jokereihin ("glob"), joilla on osittain sama toiminnallisuus (vrt muoto "*" ja ".*").
Säännöllisistä lausekkeista on yleisesti käytössä kolme tyyppiä: ''tavallinen'' (engl. basic), laajennettu (engl. extended) ja ''[[Perl]]-tyyppinen''. Varsinkin useassa järjestelmässä käytettäviä [[skripti|skriptejä]] kirjoitettaessa pitää olla huolellinen, mikäli käyttää tavallisesta poikkeavia ilmaisuja. Tässä ohjeessa esitetty syntaksi on yhteensopiva Linuxin [[GNU]]-grepin laajennetun syntaksin kanssa jollei toisin mainita.
 
Säännöllisiä lausekkeita ei pidä sekoittaa tiedostonimi-jokereihin ([[glob]]), joilla on samankaltainen toiminnallisuus (vrt. <tt>*</tt> ja <tt>.*</tt>).


== 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]].
Tietojenkäsittelytieteessä puhutaan [[wikipedia:fi:säännöllinen kieli|säännöllisestä kielestä]], joka voidaan tunnistaa [[wikipedia:fi:äärellinen automaatti|äärellisellä automaatilla]]. Säännöllisten lauskkeiden historia juontaa juurensa siten 50- ja 60-luvuille [[wikipedia:fi:tietojenkäsittelytiede|tietojenkäsittelytieteen]] syntyaikohiin. [[Unix]]-järjestelmissä säännöllisiä lausekkeita on voinut hyödyntää aina ensimmäisistä versioista lähtien. Ensimmäinen grep-ohjelma kirjoitettiin ilmeisesti vuonna 1973.<sup>[http://www.columbia.edu/~rh120/ch001j.c11]</sup>
 
Säännöllisiä lausekkeita voi hyödyntää monissa ohjelmointikielissä (mm. Perl, Java, Python, ECMAScript). Mille tahansa [[wikipedia:en:Turing complete|Turing-täydelliselle]] ohjelmointikielelle voidaan myös aina kirjoittaa säännöllisten lausekkeiden [[wikipedia:fi:Ohjelmointikielen tulkki|tulkki]].


== Johdatus säännöllisiin lausekkeisiin ==
== Johdatus säännöllisiin lausekkeisiin ==
Rivi 110: Rivi 114:


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.
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.
'''Huom!''' Operaattori <tt>{n,m}</tt> ei ole tuettu kaikissa säännöllisten lausekkeiden toteutuksissa. GNU grep tukee niitä laajennetussa tilassa (<tt>egrep</tt>).


===== Huomautuksia =====
===== Huomautuksia =====
Rivi 237: Rivi 243:
mutta ei
mutta ei
  sepe
  sepe


====Merkkiluokat: <tt>[]</tt>====
====Merkkiluokat: <tt>[]</tt>====
Rivi 253: Rivi 258:
  [thlTHL]upu
  [thlTHL]upu


Hakasulkujen välissä voidaan myös määritellä [[locale|LC_COLLATE]] mukaisen aakkoston mukaisia välejä väliviivalla <tt>-</tt>. Tällöin  
Hakasulkujen välissä voidaan myös määritellä [[lokaali]]n 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 267: Rivi 272:
  '''Osasto '''J
  '''Osasto '''J


”Osasto b” ja ”Osasto È” saattavat sisältyä, riippuen lokaalista.
On huomioitavaa, että myös kohteet ”Osasto b” tai ”Osasto È” saattavat vastata yllä esitettyä lausketta joissain [[lokaali|lokaaleissa]].
 
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 306: Rivi 305:


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>.
=====POSIX-merkkiluokat=====
Joitain erikoismerkkiluokkia on määrätty ennakkoon grepissä. Esimerkiksi
*<tt><nowiki>[:digit:]</nowiki></tt> vastaa mitä tahansa numeroa
*<tt><nowiki>[:alpha:]</nowiki></tt> vastaa mitä tahansa kirjainta
*<tt><nowiki>[:alnum:]</nowiki></tt> vastaa mitä tahansa kirjainta tai numeroa
*<tt><nowiki>[:space:]</nowiki></tt> vastaa mitä tahansa tyhjää (esim. välilyönti, tabulaattori) merkkiä
Muita tällaisia ovat <tt><nowiki>[:lower:]</nowiki></tt>, <tt><nowiki>[:upper:]</nowiki></tt>, <tt><nowiki>[:xdigit:]</nowiki></tt>, <tt><nowiki>[:blank:]</nowiki></tt>, <tt><nowiki>[:punct:]</nowiki></tt>, <tt><nowiki>[:print:]</nowiki></tt>, <tt><nowiki>[:cntrl:]</nowiki></tt> ja <tt><nowiki>[:graph:]</nowiki></tt>.
Merkkiluokat tulee laittaa lisäksi ulompien hakasulkujen <tt>[]</tt> sisään. Esimerkiksi
<nowiki>[[:upper:]]</nowiki>+
joka vastaa yleensä ilmaisua
[A-Z]+
eli mielivaltainen (vähintään yksi) määrä isoja kirjaimia A-Z.
'''Huom!''' Merkkiluokkia käytettäessä on huomioitava, että käytetty lokaali vaikuttaa ratkaisevasti siihen, mitä merkkejä luokkaan sisältyy. Siksi niitä ei voi käyttää tietoturvatarkistuksiin muuta kuin ennalta tiedetyillä lokaaleilla.


====Pako-operaattori: <tt>\</tt>====
====Pako-operaattori: <tt>\</tt>====
Rivi 395: Rivi 411:
  $ 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>.


===== Laajennetut säännölliset lausekkeet: egrep =====
Esimerkissä käytettiin komentoa <tt>egrep</tt>. Se on oikopolku grepin [[valitsin|valitsimelle]] <tt>-E</tt>, joka ottaa säännöllisten lausekkeiden laajennetun (engl. extended) 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-operaattorin <tt>\</tt>.
===== Prosessoitu tuloste: awk =====
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 415: Rivi 434:


== 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.  
Lukuunottamatta operaattoria <tt>{n,m}</tt> ja POSIX-luokkia (<tt>[[:luokka:]]</tt> jne.) yllä esitetty on pitkälti universaalisti tuettua säännöllisten lausekkeiden eri toteutuksissa. Monissa toteutuksissa on kuitenkin tehty laajennuksia tähän, mutta esim. [[grep]] ei tue seuraavia.  


=== Pakoluokat ===
=== Pakoluokat ===
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''.
Jos halutaan kirjoittaa lauseke, 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''. Ne muistuttavat läheisesti [[#POSIX-merkkiluokat|POSIX-merkkiluokkia]], mutta ovat lyhyempiä.


{| style="border-style: solid; border-collapse: collapse" border="1"
{| style="border-style: solid; border-collapse: collapse" border="1"
150

muokkausta

Navigointivalikko