Ero sivun ”Säännöllinen lauseke” versioiden välillä
p (→Aiheesta muualla: hups) |
(uudelleenkirjoitettu ohjemuotoon) |
||
Rivi 1: | Rivi 1: | ||
Säännöllinen lauseke (engl. regular expression, regexp) on | '''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 == | ||
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]]. | |||
==== | == Johdatus säännöllisiin lausekkeisiin == | ||
*' | |||
*' | ===Perusteet=== | ||
Säännöllinen lauseke joko ''vastaa'' tai ''ei vastaa'' merkkijonoa. Kutsutaan säännöllistä lauseketta ''lausekkeeksi'' ja merkkijonoa, jonka vastaavuus lausekkeeseen halutaan selvittää, ''kohteeksi''. | |||
===[[ | |||
Lausekkeen yksinkertaiset kirjoitusmerkit vastaavat yksi-yhteen kohteen kirjoitusmerkkejä. Tämän vuoksi lauseke | |||
abba | |||
vastaa yllätyksettömästi kohdetta | |||
'''abba''' | |||
mutta ei kohdetta | |||
bono | |||
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 | |||
vastaa kohdetta | |||
bo'''abba'''bo | |||
ja | |||
dada'''abba'''gada | |||
mutta ei silti kohdetta | |||
b'''abb'''bab | |||
===Operaattorit=== | |||
Yksi-yhteen vastaavien kirjoitusmerkkien lisäksi säännöllisissä lausekkeissa on mahdollisuus käyttää erilaisia ''operaattorimerkkejä'', joilla on lausekkeessa erikoismerkitys. | |||
====Vaihtoehtoisuusoperaattori: <tt>|</tt>==== | |||
Näistä ensimmäinen on operaattori <tt>|</tt>, joka tarkoittaa ''vaihtelua'' tai ''alternointia'' (engl. alternation). Sen merkitys on sama kuin luonnollisen kielen sanalla "tai". Lauseke | |||
omena|luumu | |||
vastaa sekä kohteita | |||
'''omena''' | |||
että | |||
'''luumu''' | |||
Kun lisäksi muistamme yltä, että komentorivityökalujen tapauksessa kohde voi sisältää ei-vastaavia merkkejä sekä alussa että lopussa, vastaa ylläoleva lauseke <tt>omena|luumu</tt> myös merkkijonoja | |||
uuni'''omena''' | |||
tai | |||
'''luumu'''soppa | |||
Huomaa kuitenkin, että seuraavassa kohteessa vain ensimmäinen esiintymä vastaa lauseketta | |||
kotimainen '''omena'''-luumuhillo | |||
====Toisto-operaattorit==== | |||
Merkeillä <tt>*</tt>, <tt>+</tt>, <tt>?</tt> ja ilmaisulla <tt>{n,m}</tt> on säännöllisissä lausekkeissa erikoismerkitys, joka vaikuttaa niitä ''välittömästi edeltävään'' merkkiin. | |||
=====Mielivaltaisen monta: <tt>*</tt>===== | |||
Operaattori <tt>*</tt> tarkoittaa ''"edellinen toistettuna mielivaltaisen monta kertaa, tai ei kertaakaan"''. Siten lauseke | |||
ab*a | |||
vastaa kaikkia seuraavia kohteita: | |||
'''abbbbbbbbbbbbbbbbba''' | |||
'''abbba''' | |||
'''abba''' | |||
'''aba''' | |||
'''aa''' | |||
mutta ei seuraavia: | |||
'''a'''cccca | |||
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>===== | |||
Operaattori <tt>+</tt> tarkoittaa ''"edellinen toistettuna mielivaltaisen monta kertaa, mutta vähintään kerran"''. Siten lauseke | |||
ab+a | |||
vastaa seuraavia kohteita: | |||
'''abbbbbbbbbbbbbbbbba''' | |||
'''abbba''' | |||
'''abba''' | |||
'''aba''' | |||
mutta ei seuraavia: | |||
'''a'''a | |||
'''a'''cccca | |||
bba | |||
=====Ehdollinen: <tt>?</tt>===== | |||
Operaattori <tt>?</tt> tarkoittaa ''"edellinen kerran, tai ei kertaakaan''". Siten lauseke | |||
ab?a | |||
vastaa seuraavia kohteita: | |||
'''aba''' | |||
'''aa''' | |||
mutta ei mitään seuraavista: | |||
'''ab'''bbbbbbbbbbbbbbbba | |||
'''ab'''bba | |||
'''ab'''ba | |||
'''a'''cccca | |||
bba | |||
=====n:stä m:n kertaan: <tt>{n, m}</tt>===== | |||
Aina yllä olevat operaattorit <tt>*</tt>, <tt>+</tt> ja <tt>?</tt> eivät riitä, vaan jotain merkkiä tarvitsee vastata juuri tietyn määrän toistoja. Voitaisiin toki kirjoittaa | |||
aaaa?a? | |||
jos halutaan vastata | |||
aaa | |||
aaaa | |||
aaaaa | |||
mutta voidaan kirjoittaa lyhyemmin | |||
a{3,5} | |||
Tämä tarkoittaa, että edeltävää merkkiä <tt>a</tt> voi esiintyä kolmesta viiteen kertaan. Käytetään yleisesti tästä ilmaisusta mallia <tt>{n,m}</tt>, jossa <tt>n</tt> ja <tt>m</tt> ovat mielivaltaisia kokonaislukuja, tarkoittaen ''"n:stä m:n kertaan"''. | |||
Kumpi tahansa numeroista <tt>n</tt> ja <tt>m</tt> voidaan jättää pois. Täten ilmaisu | |||
{n} | |||
tarkoittaa ''"tasan n kertaa"'. Ilmaisu | |||
{n,} | |||
tarkoittaa ''"vähintään n kertaa"''. Ilmaisu | |||
{,m} | |||
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 ===== | |||
Operaattoreita voi yhdistää mielivaltaisesti toisiinsa. Siten lauseke | |||
hur+a*!* | |||
vastaavaa kaikkia seuraavia kohteita: | |||
'''hur''' | |||
'''hurr''' | |||
'''hurra''' | |||
'''hurraa''' | |||
'''hurraa!''' | |||
'''hurrraaa!!!!''' | |||
jne. | |||
Toisaalta lauseke ''ei vastaa'' mitään seuraavista kohteista: | |||
burraa! | |||
'''hu'''aa!! | |||
'''hu'''uuurraa!! | |||
'''hurr'''urrur!! | |||
jne. | |||
Tässä vaiheessa on hyvä varmistaa, että ymmärtää edellä esitetyn esimerkin kokonaisuudessaan. | |||
===Sulut: <tt>(</tt> ja <tt>)</tt>=== | |||
'''Kysymys:''' Jos halutaan vastata kohdetta <tt>hUrrUrrUrr</tt> siten, että merkkijono <tt>Urr</tt> voi esiintyä kohteessa äärettömän monta kertaa, miten tulee toimia? | |||
'''Vastaus:''' Tämä on mahdotonta tähän mennessä esitetyillä operaattoreilla. Voisimme toki kirjoittaa <tt>hU+r+r+</tt> tai vastaavaa, mutta tämä vastaisi vain kohteita kuten <tt>hUUrrrr</tt>. Tarvitsemme selvästi uuden operaattorin; ''sulut''. | |||
Merkeillä <tt>(</tt> ja <tt>)</tt> voidaan määrittää lausekkeen osia, jotka samaan tapaan kuin koulumatematiikassa lasketaan ''ennen'' laskun muita osia. Koska säännöllisissä lausekkeissa ei kuitenkaan lasketa mitään, havainnollistetaan sulkujen merkitystä esittämällä ratkaisu yllä olevaan kysymykseen. | |||
Lauseke | |||
h(Urr)+ | |||
vastaa kohteita | |||
'''hUrr''' | |||
'''hUrrUrr''' | |||
'''hUrrUrrUrr''' | |||
'''hUrrUrrUrrUrr''' | |||
jne. jne. Lauseke ei vastaa seuraavia kohteita: | |||
'''h'''Arr | |||
'''h'''Err | |||
burr | |||
Samoin kohde | |||
'''hUr''' | |||
näyttää oikealta, mutta jää kuitenkin liian lyhyeksi, sillä sulkujen sisältö on löydyttävä kohteesta aina ''kokonaan''. Siksi kohde <tt>hUr</tt> <u>ei</u> vastaa lauseketta <tt>h(Urr)+</tt>. | |||
====Esimerkkejä==== | |||
Sulkuja voi yhdistellä mielivaltaisesti kaikkiin operaattoreihin <tt>*</tt>, <tt>+</tt>, <tt>?</tt> ja <tt>|</tt>. Seuraavassa on annettu sarja lausekkeita, sekä esimerkkejä kutakin vastaavista ja vastaamattomista kohteista: | |||
Lauseke | |||
d(ii)?pada+(pa|ba)? | |||
vastaa esimerkiksi seuraavia kohteita | |||
'''diipadaaba''' | |||
'''diipadaapa''' | |||
'''dpadaapa''' | |||
'''dpadaaba''' | |||
'''diipadaaaaapa''' | |||
'''diipadaaaaaba''' | |||
'''diipada''' | |||
'''diipada''' | |||
'''diipadaaa''' | |||
'''diipadaaaa''' | |||
mutta ei mitään seuraavista | |||
'''di'''padaapa | |||
'''diipad'''uu | |||
'''diipad''' | |||
Viimeinen esimerkki jää lyhyeksi, sillä merkki <tt>a</tt> on lausekkeessa pakollinen vähintään kerran. | |||
Lauseke | |||
(hi|ha|ho)+ | |||
vastaa mitä tahansa kohdetta, jossa esiintyy mikä tahansa määrä merkkijonoja <tt>hi</tt>, <tt>ha</tt> ja <tt>ho</tt> peräkkäin mielivaltaisen monta kertaa, kuitenkin vähintään kerran. Lauseke vastaa siis kaikkia seuraavia: | |||
'''hi''' | |||
'''ha''' | |||
'''ho''' | |||
'''hihi''' | |||
'''haha''' | |||
'''hiha''' | |||
'''hoho''' | |||
'''hihaho''' | |||
'''hahohihohahi''' | |||
mutta ei | |||
'''h'''e | |||
'''h'''u | |||
'''h'''uhu | |||
'''h'''ehe | |||
===Yhtä merkkiä vastaavat erikoismerkit=== | |||
Säännöllisissä lausekkeissa voi esiintyä myös joitain erikoismerkkejä, jotka eivät ole operaattoreita, eli ne eivät vaikuta niitä edeltäviin sulkuihin tai merkkeihin. Ne voitaisiin aina kirjoittaa lausekkeilla muotoa | |||
(merkki1|merkki2|merkki3|merkki4|...|merkkiN) | |||
mutta tämä on varsin työlästä ja epäselkeää. Siksi säännöllisissä lausekkeissa on joitain erikoismerkkejä, jotka ovat oikopolkuja monimutkaisten vaihtoehtoisuuslausekkeiden kirjoittamiseen. | |||
====Jokerimerkki: <tt>.</tt>==== | |||
Merkillä <tt>.</tt> (piste) on erikoismerkitys. Se vastaa aina ''mitä tahansa'' merkkiä. Lauseke | |||
.* | |||
vastaa siis kaikkia mahdollisia kohteita - jopa tyhjää merkkijonoa, sillä operaattori <tt>*</tt> tarkoittaa, että erikoisoperaattori "mikä tahansa merkki" voi esiintyä myös nolla kertaa. | |||
Lauseke | |||
(h.)+ | |||
vastaa siten kaikkia seuraavista: | |||
'''ha''' | |||
'''he''' | |||
'''hi''' | |||
'''hy''' | |||
'''hr''' | |||
'''hihrhy''' | |||
mutta ei | |||
rh | |||
ah | |||
oh | |||
ih | |||
'''h''' | |||
Viimeinen esimerkki jää jälleen lyhyeksi, sillä <tt>.</tt> ei vastaa kuitenkaan "tyhjää" merkkiä. | |||
Lauseke | |||
.upu | |||
vastaa | |||
'''tupu''' | |||
'''hupu''' | |||
'''lupu''' | |||
'''Tupu''' | |||
'''Hupu''' | |||
'''Lupu''' | |||
mutta myös | |||
'''supu''' | |||
mutta ei | |||
sepe | |||
====Merkkiluokat: <tt>[]</tt>==== | |||
Jos halutaan korjata ylläoleva Ankanpoika-esimerkki, voitaisiin kirjoittaa: | |||
(t|h|l|T|H|L)upu | |||
joka vastaisi vain ja ainoastaan: | |||
'''tupu''' | |||
'''hupu''' | |||
'''lupu''' | |||
'''Tupu''' | |||
'''Hupu''' | |||
'''Lupu''' | |||
Merkkien <tt>[]</tt> avulla voidaan määritellä kirjainluokkia siten, että seuraava merkki kohteessa vastaa vain ja ainoastaan jotain hakasulkujen välissä olevaa kirjainta. Siten äskeistä täysin vastaa lauseke on | |||
[thlTHL]upu | |||
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] | |||
vastaa kaikkia vuosilukuja välillä 1940-2099. Samoin | |||
Osasto [A-I] | |||
vastaa | |||
'''Osasto A''' | |||
'''Osasto B''' | |||
'''Osasto C''' | |||
... | |||
'''Osasto H''' | |||
'''Osasto I''' | |||
mutta ei | |||
'''Osasto '''J | |||
Jos merkki <tt>-</tt> halutaan sisällyttää hakasulkuilmaisuun, se jätetään viimeiseksi. Esim. | |||
Ala[ -]aste | |||
vastaa | |||
'''Ala aste''' | |||
'''Ala-aste''' | |||
Jos oikea hakasulku (<tt>]</tt>) halutaan sisällyttää hakasulkuilmaukseen, se laitetaan hakasulkujen ensimmäiseksi merkiksi. Esim. | |||
[]abcdef]+ | |||
vastaa | |||
'''a''' | |||
'''b''' | |||
''']''' | |||
'''ab]''' | |||
'''d]f''' | |||
jne., mutta ei | |||
[gi | |||
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åäö]+ | |||
vastaa mitä tahansa pelkistä konsonanteista, välimerkeistä ja numeroista koostuvaa kohdetta, kuten | |||
'''prrr''' | |||
'''123''' | |||
'''hkr''' | |||
'''brr-hrr''' | |||
jne. Mutta ei | |||
au | |||
aiai | |||
jne. | |||
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>==== | |||
Jos halutaan vastata jotain merkkiä, joka on määritelty operaattoriksi säännöllisissä lausekkeissa, sitä ei voida kirjoittaa sellaisenaan lausekkeeseen. Jos halutaan vastata tarkalleen jotain seuraavista | |||
Mitä? | |||
Missä? | |||
Milloin? | |||
ei voida kirjoittaa lauseketta | |||
(Mi(tä|ssä|lloin))? | |||
koska kysymysmerkki <tt>?</tt> lopussa vain ehdollista koko ulomman sulkuilmaisun, ja koko lauseke vastaisi siis vain joko tyhjää merkkijonoa tai kysymysmerkitöntä kysymyssanaa. | |||
Tarvitaan pako-operaattoria <tt>\</tt>. Merkin <tt>?</tt> tai ylipäänsä minkä tahansa opraattorimerkin erikoismerkityksen voi poistaa asettamalla sen eteen kenoviivan. Tällöin kenoviivaa välittömästi seuraava merkki täytyy esiintyä kohteessa sellaisenaan. Oikea tapa kirjoittaa yllä oleva lauseke olisi siten | |||
(Mi(tä|ssä|lloin))\? | |||
Tämä vastaa vain ja ainoastaan haluttuja merkkijonoja. | |||
Seuraavat operaattorit on merkittävä pako-operaattorilla, jos niitä ei haluta tulkittavan erikoismerkeiksi: | |||
( ) | * + ? { } [ ] ^ $ \ | |||
Siis, jos halutaan vastata kohteessa kenoviivaa, on kirjoitettava <tt>\\</tt>. Esimerkiksi Windows-polku: | |||
''<asema>'':\Dokumentit\''<nimi>''.(doc, docx tai odt) | |||
voidaan löytää esim. seuraavalla säännöllisellä lausekkeella: | |||
[A-Z]:\\Dokumentit\\[a-öA-Ö0-9 _-]+\.(doc|docx|odt) | |||
=== Rivin alku ja loppu: <tt>^</tt> ja <tt>$</tt>=== | |||
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$ | |||
vastaa vain riviä | |||
'''abba''' | |||
mutta ei esimerkiksi | |||
babba | |||
abbab | |||
babbab | |||
'''ab'''a | |||
'''abb'''bba | |||
==== Esimerkki ==== | |||
Merkit <tt>^</tt> ja <tt>$</tt> antavat viimeisen silauksen grepin tehokkaaseen hyödyntämiseen. Nyt esimerkiksi, jos tulostetaan kaikki [[prosessi]]t komennolla <tt>[[ps]] -ef</tt>, saadaan yleensä jokseenkin tälläinen listaus (esimerkissä palvelinkone): | |||
$ ps -ef | |||
UID PID PPID C STIME TTY TIME CMD | |||
root 1 0 0 Jan21 ? 00:00:34 init [2] | |||
root 1425 1 0 Jan31 ? 00:00:00 /usr/sbin/xinetd | |||
qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send | |||
qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 | |||
root 3993 3986 0 Jan21 ? 00:00:00 qmail-lspawn | /usr/bin/deliverquota ./Maildir | |||
qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn | |||
qmailq 3995 3986 0 Jan21 ? 00:00:00 qmail-clean | |||
root 5566 1 0 Jan21 ? 00:00:05 /usr/sbin/apache2 -k start | |||
root 6091 1 0 Jan21 ? 00:00:03 /usr/sbin/cron | |||
www-data 15379 5566 0 Feb14 ? 00:00:00 /usr/sbin/apache2 -k start | |||
www-data 15386 5566 0 Feb14 ? 00:00:00 /usr/sbin/apache2 -k start | |||
root 21684 32395 0 20:37 ? 00:00:00 sshd: user [priv] | |||
user 21688 21684 0 20:37 ? 00:00:00 sshd: user@pts/1 | |||
user 21689 21688 0 20:37 pts/1 00:00:00 -bash | |||
user 21705 21689 0 20:37 pts/1 00:00:00 ps -ef | |||
syslog 32279 1 0 Jan21 ? 00:00:07 /sbin/syslogd -u syslog | |||
bind 32351 1 0 Jan31 ? 00:00:00 /usr/sbin/named | |||
root 32395 1 0 Jan21 ? 00:00:22 /usr/sbin/sshd | |||
(... jne ...) | |||
Jos haluamme ylläolevasta listasta vain "qmail" -alkuisten [[käyttäjä|käyttäjien]] prosessit, voisimme kirjoittaa | |||
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: | |||
$ ps -ef | grep qmail | |||
qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send | |||
qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 | |||
root 3993 3986 0 Jan21 ? 00:00:00 qmail-lspawn | /usr/bin/deliverquota ./Maildir | |||
qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn | |||
qmailq 3995 3986 0 Jan21 ? 00:00:00 qmail-clean | |||
Ratkaisu qmail -alkuisten käyttäjien prosessien listaamiseen on: | |||
$ ps -ef | grep ^qmail. | |||
qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send | |||
qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 | |||
qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn | |||
qmailq 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 merkki (ilmaisu <tt>.</tt>). Grep tulostaa vain lausketta vastaavat rivit, ja tulos on haluttu. | |||
===== 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|komeotulkissa]] eivät aiheuta ongelmia. | |||
$ echo moi | egrep m(o|a)i | |||
-bash: syntax error near unexpected token `(' | |||
Sululla <tt>(</tt> on erikoismerkitys komentotulkissa, samoin merkillä <tt>[[putki||]]</tt>. Ratkaisu: | |||
$ echo moi | egrep 'm(o|a)i' | |||
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: | |||
$ ps -ef | awk '/^qmail./ { print $2 }' | |||
3986 | |||
3990 | |||
3994 | |||
3995 | |||
== Esimerkkejä lausekkeista == | |||
Web-kuva: | |||
[^ ]+\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF) | |||
Päivämäärä muotoa pp.kk.vvvv: | |||
[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4} | |||
2-merkkinen [[wikipedia:fi:heksadesimaalijärjestelmä|heksadesimaali]]: | |||
[0-9A-Fa-f]{2} | |||
Sähköpostiosoite: | |||
[a-zA-Z0-9_]+@[a-zA-Z0-9_\.]+\.[a-zA-Z]{2,3} | |||
== 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 === | |||
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" | |||
|+'''Pakoluokat''' | |||
|- | |||
! Ilmaisu !! Merkitys !! Vastaava hakasulkuilmaus | |||
|- | |||
| <tt>\w</tt> || Mikä tahansa kirjain, numero tai alaviiva. || <tt>[a-zA-Z0-9_]</tt> | |||
|- | |||
| <tt>\W</tt> || Äskeisen vastakohta; mikä tahansa muu kuin kirjain, numero tai alaviiva. || <tt>[^a-zA-Z0-9_]</tt> | |||
|- | |||
| <tt>\s</tt> || Mikä tahansa tyhjä merkki (esim. välilyönti tai tabulaattori) || esim. <tt>[ \t]</tt>, jossa <tt>\t</tt> tabulaattorimerkki | |||
|- | |||
| <tt>\S</tt> || Äskeisen vastakohta; mikä tahansa ei-tyhjä merkki || esim. <tt>[^ \t]</tt> | |||
|- | |||
| <tt>\d</tt> || Mikä tahansa numero. || <tt>[0-9]</tt> | |||
|- | |||
| <tt>\D</tt> || Äskeisen vastakohta; mikä tahansa ei-numero. || <tt>[^0-9]</tt> | |||
|} | |||
Lauseke | |||
\d+ | |||
vastaa siis kaikkia numeroita aivan siinä missä myös | |||
[0-9]+ | |||
==Katso myös== | |||
* [[Komentorivin perusteet]] | |||
* [[Grep]] ja [[Awk]] | |||
** [[Putki]] | |||
* [[Ed]] ja [[Sed]]: tuki säännöllisille lausekkeille | |||
* [[Vi]] ja [[vim]]: näiden graaffinen tila | |||
* [[Emacs]] | |||
==Aiheesta muualla== | ==Aiheesta muualla== | ||
Rivi 27: | Rivi 442: | ||
*[[wikipedia:fi:turingin kone|Turingin kone]] | *[[wikipedia:fi:turingin kone|Turingin kone]] | ||
*[http://www.ohjelmointiputka.net/opas.php?tunnus=phpsl Säännölliset lausekkeet PHP:ssä] -opas Ohjelmointiputkassa | *[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. | |||
[[Luokka:Käsitteet]] | [[Luokka:Käsitteet]] | ||
[[Luokka:Komentorivi]] | |||
[[Luokka:Perustietoa]] |
Versio 17. helmikuuta 2010 kello 01.20
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 putkittamiseen yhdistettynä tärkeimpiä työkaluja, joita komentorivin edistynyt käyttö edellyttää.
Teoriaa
Tietojenkäsittelytieteessä puhutaan säännöllisestä kielestä, joka voidaan tunnistaa äärellisellä automaatilla. Säännöllisiä lausekkeita käytetään myös monissa ohjelmointikielissä (mm. Perl, Java, Python, ECMAScript). Mille tahansa Turing-täydelliselle ohjelmointikielelle voidaan kuitenkin aina kirjoittaa säännöllisten lausekkeiden tulkki.
Johdatus säännöllisiin lausekkeisiin
Perusteet
Säännöllinen lauseke joko vastaa tai ei vastaa merkkijonoa. Kutsutaan säännöllistä lauseketta lausekkeeksi ja merkkijonoa, jonka vastaavuus lausekkeeseen halutaan selvittää, kohteeksi.
Lausekkeen yksinkertaiset kirjoitusmerkit vastaavat yksi-yhteen kohteen kirjoitusmerkkejä. Tämän vuoksi lauseke
abba
vastaa yllätyksettömästi kohdetta
abba
mutta ei kohdetta
bono
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
vastaa kohdetta
boabbabo
ja
dadaabbagada
mutta ei silti kohdetta
babbbab
Operaattorit
Yksi-yhteen vastaavien kirjoitusmerkkien lisäksi säännöllisissä lausekkeissa on mahdollisuus käyttää erilaisia operaattorimerkkejä, joilla on lausekkeessa erikoismerkitys.
Vaihtoehtoisuusoperaattori: |
Näistä ensimmäinen on operaattori |, joka tarkoittaa vaihtelua tai alternointia (engl. alternation). Sen merkitys on sama kuin luonnollisen kielen sanalla "tai". Lauseke
omena|luumu
vastaa sekä kohteita
omena
että
luumu
Kun lisäksi muistamme yltä, että komentorivityökalujen tapauksessa kohde voi sisältää ei-vastaavia merkkejä sekä alussa että lopussa, vastaa ylläoleva lauseke omena|luumu myös merkkijonoja
uuniomena
tai
luumusoppa
Huomaa kuitenkin, että seuraavassa kohteessa vain ensimmäinen esiintymä vastaa lauseketta
kotimainen omena-luumuhillo
Toisto-operaattorit
Merkeillä *, +, ? ja ilmaisulla {n,m} on säännöllisissä lausekkeissa erikoismerkitys, joka vaikuttaa niitä välittömästi edeltävään merkkiin.
Mielivaltaisen monta: *
Operaattori * tarkoittaa "edellinen toistettuna mielivaltaisen monta kertaa, tai ei kertaakaan". Siten lauseke
ab*a
vastaa kaikkia seuraavia kohteita:
abbbbbbbbbbbbbbbbba abbba abba aba aa
mutta ei seuraavia:
acccca 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: +
Operaattori + tarkoittaa "edellinen toistettuna mielivaltaisen monta kertaa, mutta vähintään kerran". Siten lauseke
ab+a
vastaa seuraavia kohteita:
abbbbbbbbbbbbbbbbba abbba abba aba
mutta ei seuraavia:
aa acccca bba
Ehdollinen: ?
Operaattori ? tarkoittaa "edellinen kerran, tai ei kertaakaan". Siten lauseke
ab?a
vastaa seuraavia kohteita:
aba aa
mutta ei mitään seuraavista:
abbbbbbbbbbbbbbbbba abbba abba acccca bba
n:stä m:n kertaan: {n, m}
Aina yllä olevat operaattorit *, + ja ? eivät riitä, vaan jotain merkkiä tarvitsee vastata juuri tietyn määrän toistoja. Voitaisiin toki kirjoittaa
aaaa?a?
jos halutaan vastata
aaa aaaa aaaaa
mutta voidaan kirjoittaa lyhyemmin
a{3,5}
Tämä tarkoittaa, että edeltävää merkkiä a voi esiintyä kolmesta viiteen kertaan. Käytetään yleisesti tästä ilmaisusta mallia {n,m}, jossa n ja m ovat mielivaltaisia kokonaislukuja, tarkoittaen "n:stä m:n kertaan".
Kumpi tahansa numeroista n ja m voidaan jättää pois. Täten ilmaisu
{n}
tarkoittaa "tasan n kertaa"'. Ilmaisu
{n,}
tarkoittaa "vähintään n kertaa". Ilmaisu
{,m}
tarkoittaa "korkeintaan m kertaa".
Sivuhuomatuksena todettakoon, että yllä olevan perusteella lyhyemmät operaattorit *, + ja ? voitaisiin aina korvata ilmaisuilla {0,}, {1,} ja {0,1} vastaavasti.
Huomautuksia
Operaattoreita voi yhdistää mielivaltaisesti toisiinsa. Siten lauseke
hur+a*!*
vastaavaa kaikkia seuraavia kohteita:
hur hurr hurra hurraa hurraa! hurrraaa!!!!
jne.
Toisaalta lauseke ei vastaa mitään seuraavista kohteista:
burraa! huaa!! huuuurraa!! hurrurrur!!
jne.
Tässä vaiheessa on hyvä varmistaa, että ymmärtää edellä esitetyn esimerkin kokonaisuudessaan.
Sulut: ( ja )
Kysymys: Jos halutaan vastata kohdetta hUrrUrrUrr siten, että merkkijono Urr voi esiintyä kohteessa äärettömän monta kertaa, miten tulee toimia?
Vastaus: Tämä on mahdotonta tähän mennessä esitetyillä operaattoreilla. Voisimme toki kirjoittaa hU+r+r+ tai vastaavaa, mutta tämä vastaisi vain kohteita kuten hUUrrrr. Tarvitsemme selvästi uuden operaattorin; sulut.
Merkeillä ( ja ) voidaan määrittää lausekkeen osia, jotka samaan tapaan kuin koulumatematiikassa lasketaan ennen laskun muita osia. Koska säännöllisissä lausekkeissa ei kuitenkaan lasketa mitään, havainnollistetaan sulkujen merkitystä esittämällä ratkaisu yllä olevaan kysymykseen.
Lauseke
h(Urr)+
vastaa kohteita
hUrr hUrrUrr hUrrUrrUrr hUrrUrrUrrUrr
jne. jne. Lauseke ei vastaa seuraavia kohteita:
hArr hErr burr
Samoin kohde
hUr
näyttää oikealta, mutta jää kuitenkin liian lyhyeksi, sillä sulkujen sisältö on löydyttävä kohteesta aina kokonaan. Siksi kohde hUr ei vastaa lauseketta h(Urr)+.
Esimerkkejä
Sulkuja voi yhdistellä mielivaltaisesti kaikkiin operaattoreihin *, +, ? ja |. Seuraavassa on annettu sarja lausekkeita, sekä esimerkkejä kutakin vastaavista ja vastaamattomista kohteista:
Lauseke
d(ii)?pada+(pa|ba)?
vastaa esimerkiksi seuraavia kohteita
diipadaaba diipadaapa dpadaapa dpadaaba diipadaaaaapa diipadaaaaaba diipada diipada diipadaaa diipadaaaa
mutta ei mitään seuraavista
dipadaapa diipaduu diipad
Viimeinen esimerkki jää lyhyeksi, sillä merkki a on lausekkeessa pakollinen vähintään kerran.
Lauseke
(hi|ha|ho)+
vastaa mitä tahansa kohdetta, jossa esiintyy mikä tahansa määrä merkkijonoja hi, ha ja ho peräkkäin mielivaltaisen monta kertaa, kuitenkin vähintään kerran. Lauseke vastaa siis kaikkia seuraavia:
hi ha ho hihi haha hiha hoho hihaho hahohihohahi
mutta ei
he hu huhu hehe
Yhtä merkkiä vastaavat erikoismerkit
Säännöllisissä lausekkeissa voi esiintyä myös joitain erikoismerkkejä, jotka eivät ole operaattoreita, eli ne eivät vaikuta niitä edeltäviin sulkuihin tai merkkeihin. Ne voitaisiin aina kirjoittaa lausekkeilla muotoa
(merkki1|merkki2|merkki3|merkki4|...|merkkiN)
mutta tämä on varsin työlästä ja epäselkeää. Siksi säännöllisissä lausekkeissa on joitain erikoismerkkejä, jotka ovat oikopolkuja monimutkaisten vaihtoehtoisuuslausekkeiden kirjoittamiseen.
Jokerimerkki: .
Merkillä . (piste) on erikoismerkitys. Se vastaa aina mitä tahansa merkkiä. Lauseke
.*
vastaa siis kaikkia mahdollisia kohteita - jopa tyhjää merkkijonoa, sillä operaattori * tarkoittaa, että erikoisoperaattori "mikä tahansa merkki" voi esiintyä myös nolla kertaa.
Lauseke
(h.)+
vastaa siten kaikkia seuraavista:
ha he hi hy hr hihrhy
mutta ei
rh ah oh ih h
Viimeinen esimerkki jää jälleen lyhyeksi, sillä . ei vastaa kuitenkaan "tyhjää" merkkiä.
Lauseke
.upu
vastaa
tupu hupu lupu Tupu Hupu Lupu
mutta myös
supu
mutta ei
sepe
Merkkiluokat: []
Jos halutaan korjata ylläoleva Ankanpoika-esimerkki, voitaisiin kirjoittaa:
(t|h|l|T|H|L)upu
joka vastaisi vain ja ainoastaan:
tupu hupu lupu Tupu Hupu Lupu
Merkkien [] avulla voidaan määritellä kirjainluokkia siten, että seuraava merkki kohteessa vastaa vain ja ainoastaan jotain hakasulkujen välissä olevaa kirjainta. Siten äskeistä täysin vastaa lauseke on
[thlTHL]upu
Hakasulkujen välissä voidaan myös määritellä aakkoston mukaisia välejä väliviivalla -. Tällöin
19[4-9][0-9]|20[0-9][0-9]
vastaa kaikkia vuosilukuja välillä 1940-2099. Samoin
Osasto [A-I]
vastaa
Osasto A Osasto B Osasto C ... Osasto H Osasto I
mutta ei
Osasto J
Jos merkki - halutaan sisällyttää hakasulkuilmaisuun, se jätetään viimeiseksi. Esim.
Ala[ -]aste
vastaa
Ala aste Ala-aste
Jos oikea hakasulku (]) halutaan sisällyttää hakasulkuilmaukseen, se laitetaan hakasulkujen ensimmäiseksi merkiksi. Esim.
[]abcdef]+
vastaa
a b ] ab] d]f
jne., mutta ei
[gi zo
Hakasulkuilmaisusn merkitys voidaan kääntää asettamalla hattu ^ sen ensimmäiseksi merkiksi. Tällöin hakasulkuilmaisu vastaa mitä tahansa hakasuluissa ei esiintyvää merkkiä kohteessa. Täten lauseke
[^aeiouyåäö]+
vastaa mitä tahansa pelkistä konsonanteista, välimerkeistä ja numeroista koostuvaa kohdetta, kuten
prrr 123 hkr brr-hrr
jne. Mutta ei
au aiai
jne.
Grepin hyväksymissä säännöllisissä lausekkeissa merkin ^ 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 \.
Pako-operaattori: \
Jos halutaan vastata jotain merkkiä, joka on määritelty operaattoriksi säännöllisissä lausekkeissa, sitä ei voida kirjoittaa sellaisenaan lausekkeeseen. Jos halutaan vastata tarkalleen jotain seuraavista
Mitä? Missä? Milloin?
ei voida kirjoittaa lauseketta
(Mi(tä|ssä|lloin))?
koska kysymysmerkki ? lopussa vain ehdollista koko ulomman sulkuilmaisun, ja koko lauseke vastaisi siis vain joko tyhjää merkkijonoa tai kysymysmerkitöntä kysymyssanaa.
Tarvitaan pako-operaattoria \. Merkin ? tai ylipäänsä minkä tahansa opraattorimerkin erikoismerkityksen voi poistaa asettamalla sen eteen kenoviivan. Tällöin kenoviivaa välittömästi seuraava merkki täytyy esiintyä kohteessa sellaisenaan. Oikea tapa kirjoittaa yllä oleva lauseke olisi siten
(Mi(tä|ssä|lloin))\?
Tämä vastaa vain ja ainoastaan haluttuja merkkijonoja.
Seuraavat operaattorit on merkittävä pako-operaattorilla, jos niitä ei haluta tulkittavan erikoismerkeiksi:
( ) | * + ? { } [ ] ^ $ \
Siis, jos halutaan vastata kohteessa kenoviivaa, on kirjoitettava \\. Esimerkiksi Windows-polku:
<asema>:\Dokumentit\<nimi>.(doc, docx tai odt)
voidaan löytää esim. seuraavalla säännöllisellä lausekkeella:
[A-Z]:\\Dokumentit\\[a-öA-Ö0-9 _-]+\.(doc|docx|odt)
Rivin alku ja loppu: ^ ja $
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 ^ ja $. Nämä vastaavat kohteessa rivin tai merkkijonon alkua ja loppua kuvaavia "näkymättömiä" merkkejä vastaavasti. Siten
^abba$
vastaa vain riviä
abba
mutta ei esimerkiksi
babba abbab babbab aba abbbba
Esimerkki
Merkit ^ ja $ antavat viimeisen silauksen grepin tehokkaaseen hyödyntämiseen. Nyt esimerkiksi, jos tulostetaan kaikki prosessit komennolla ps -ef, saadaan yleensä jokseenkin tälläinen listaus (esimerkissä palvelinkone):
$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jan21 ? 00:00:34 init [2] root 1425 1 0 Jan31 ? 00:00:00 /usr/sbin/xinetd qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 root 3993 3986 0 Jan21 ? 00:00:00 qmail-lspawn | /usr/bin/deliverquota ./Maildir qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn qmailq 3995 3986 0 Jan21 ? 00:00:00 qmail-clean root 5566 1 0 Jan21 ? 00:00:05 /usr/sbin/apache2 -k start root 6091 1 0 Jan21 ? 00:00:03 /usr/sbin/cron www-data 15379 5566 0 Feb14 ? 00:00:00 /usr/sbin/apache2 -k start www-data 15386 5566 0 Feb14 ? 00:00:00 /usr/sbin/apache2 -k start root 21684 32395 0 20:37 ? 00:00:00 sshd: user [priv] user 21688 21684 0 20:37 ? 00:00:00 sshd: user@pts/1 user 21689 21688 0 20:37 pts/1 00:00:00 -bash user 21705 21689 0 20:37 pts/1 00:00:00 ps -ef syslog 32279 1 0 Jan21 ? 00:00:07 /sbin/syslogd -u syslog bind 32351 1 0 Jan31 ? 00:00:00 /usr/sbin/named root 32395 1 0 Jan21 ? 00:00:22 /usr/sbin/sshd (... jne ...)
Jos haluamme ylläolevasta listasta vain "qmail" -alkuisten käyttäjien prosessit, voisimme kirjoittaa
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:
$ ps -ef | grep qmail qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 root 3993 3986 0 Jan21 ? 00:00:00 qmail-lspawn | /usr/bin/deliverquota ./Maildir qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn qmailq 3995 3986 0 Jan21 ? 00:00:00 qmail-clean
Ratkaisu qmail -alkuisten käyttäjien prosessien listaamiseen on:
$ ps -ef | grep ^qmail. qmails 3986 1 0 Jan21 ? 00:00:00 qmail-send qmaill 3990 3986 0 Jan21 ? 00:00:00 splogger qmail 2 qmailr 3994 3986 0 Jan21 ? 00:00:00 qmail-rspawn qmailq 3995 3986 0 Jan21 ? 00:00:00 qmail-clean
Hattumerkki ^ alussa vastaa jokaisen listausrivin alkua, jota pitää välittömästi seurata merkkijono qmail, ja tämän jälkeen voi tulla mikä tahansa merkki (ilmaisu .). Grep tulostaa vain lausketta vastaavat rivit, ja tulos on haluttu.
Pako komentotulkista
Jos halutaan antaa jokin monimutkaisempi ilmaisu, on hyvä asettaa säännöllinen lauseke yksinkertaisten heittomerkkien ' sisään, jotta ne regexp-operaattorit, joillla on jokin erikoismerkitys komeotulkissa eivät aiheuta ongelmia.
$ echo moi | egrep m(o|a)i -bash: syntax error near unexpected token `('
Sululla ( on erikoismerkitys komentotulkissa, samoin merkillä |. Ratkaisu:
$ echo moi | egrep 'm(o|a)i' moi
Esimerkissä käytettiin komentoa egrep. Se on oikopolku grepin valitsimelle -E, joka ottaa säännöllisten lausekkeiden laajennetun tuen käyttöön. Normaalissa käytössä (pelkkö komento grep) operaattorit ? + {} | ( ja ) eivät ole käytettävissä, paitsi asettamalla niiden eteen pako-operaattori \.
Jos ylläolevassa prosessilistausesimerkissä halutaan tulostaa pelkät prosessien PID-numerot, voidaan käyttää awk-työkalua seuraavasti:
$ ps -ef | awk '/^qmail./ { print $2 }' 3986 3990 3994 3995
Esimerkkejä lausekkeista
Web-kuva:
[^ ]+\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF)
Päivämäärä muotoa pp.kk.vvvv:
[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}
2-merkkinen heksadesimaali:
[0-9A-Fa-f]{2}
Sähköpostiosoite:
[a-zA-Z0-9_]+@[a-zA-Z0-9_\.]+\.[a-zA-Z]{2,3}
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
Jos halutaan kirjoittaa lause, joka jossain kohtaa vastaa mitä tahansa numeromerkkiä, voidaan kirjoittaa hakasulkuilmaus [0-9]. Tälläisille yleisesti käytetyille luokille on kuitenkin olemassa laajennuksissa helpompia nimiä. Kutsutaan näitä pakoluokiksi.
Ilmaisu | Merkitys | Vastaava hakasulkuilmaus |
---|---|---|
\w | Mikä tahansa kirjain, numero tai alaviiva. | [a-zA-Z0-9_] |
\W | Äskeisen vastakohta; mikä tahansa muu kuin kirjain, numero tai alaviiva. | [^a-zA-Z0-9_] |
\s | Mikä tahansa tyhjä merkki (esim. välilyönti tai tabulaattori) | esim. [ \t], jossa \t tabulaattorimerkki |
\S | Äskeisen vastakohta; mikä tahansa ei-tyhjä merkki | esim. [^ \t] |
\d | Mikä tahansa numero. | [0-9] |
\D | Äskeisen vastakohta; mikä tahansa ei-numero. | [^0-9] |
Lauseke
\d+
vastaa siis kaikkia numeroita aivan siinä missä myös
[0-9]+
Katso myös
- Komentorivin perusteet
- Grep ja Awk
- Ed ja Sed: tuki säännöllisille lausekkeille
- Vi ja vim: näiden graaffinen tila
- Emacs
Aiheesta muualla
- Säännöllinen lauseke
- Äärellinen automaatti
- Pinoautomaatti
- Turingin kone
- Säännölliset lausekkeet PHP:ssä -opas Ohjelmointiputkassa
- Regular Expression Matching Can Be Simple And Fast: Keskustelua säännöllisten lausekkeiden toteutuksesta C-kielellä englanniksi.