Metakarakters
Om het over metakarakters te kunnen hebben, dienen we eerst vast te stellen wat "normale" karakters binnen een regex betekenen. De regex kat vindt inderdaad de "kat" in de tekst De kat van de buren piest op mijn gazon, maar ook de "kat" in de winterkatalogus. Dus, reguliere expressies werken puur op tekstueel niveau; ze kijken niet naar de semantiek. Het is belangrijk in te zien dat bovenstaande regex niks meer betekent voor de regex motor betekent dan een 'c', gevolgd door een 'a', gevolgd door een 't', waar deze reeks zich dan ook mag bevinden in de tekst waar de regex op is toegepast.
Om je op weg te helpen is hier een simpel voorbeeld. fruit.txt bevat een lijstje van soorten fruit, acht in totaal, één per regel. Als je het voorbeeld eenmaal gedownload en opgeslagen hebt, open dan een console (of DOS-venster of zo) en ga naar de directory waar je het bestand hebt opgeslagen. Als je daar bent, type dan het volgende:
$ egrep peer fruit.txt
peer
Het is niet de meest spetterende demonstratie van reguliere expressies in actie, maar als je dezelfde uitvoer krijgt, namelijk peer, dan betekent dat dat je met succes je eerste regex hebt toegepsst. Aangenomen dat dit je eerste keer is, natuurlijk.
Een ander voorbeeld is:
$ egrep pe fruit.txt
appel
sinaasappel
peer
perzik
Deze is al iets interessanter. De regex pe pakt elke regel die pe bevat, benadrukkend dat reguliere expressies totaal geen oog hebben voor semantiek. Nog een instructief voorbeeld is:
$ egrep an fruit.txt
banaan
Je vraagt je misschien af wat er zo bijzonder is aan dit voorbeeld. Als je je herinnerd dat egrep alleen die regels afdrukt die het patroon passen, vraag je je misschien af hoe egrep omgaat met het toepassen van an op banaan; misschien denk je dat het de regel twee keer pakt, wat meer is dan één, en dus wordt de regel afgedrukt. Het punt is dat egrep stopt met het toepassen van de regex op de regel zodra het een match vindt. Zodra het de eerste an vindt, houdt het op met zoeken, drukt de regel af en gaat door naar de volgende.
Dit specifieke voorbeeld illustreert dat egrep niet geïnteresseerd is in wat het patroon past, of hoe vaak, maar alleen of het past of niet. Later komen we nog voorbeelden tegen waar het wel uitmaakt wat en hoe vaak iets wordt gepast. Uiteraard maken deze voorbeelden geen gebruik van egrep.
Het laatste voorbeeld van deze sectie laat een feature van egrep zien:
$ egrep -v a fruit.txt
peer
perzik
druif
bosbes
pruim
De -v optie vertelt egrep om de zin van het passen te inverteren. Hierdoor worden alleen regels afgedrukt die het patroon niet passen. En inderdaad, geen van de afgedrukte regels bevat een 'a'.
3.1. Ankers
Met ^ en $ kun je een regex dwingen om alleen aan het begin of eind van een regel te passen, respectievelijk. Zo past ^kat alleen die regels die beginnen met kat, en kat$ alleen regels die eindigen met kat.
Een probeervoorbeeld dat dezelfde fruit.txt gebruikt als in de vorige sectie is de regex ^p:
$ egrep ^p fruit.txt
peer
perzik
pruim
Zoals je ziet slaagt deze regex er niet in om appel of sinaasappel te passen. Het feit dat ze op een andere plek wel een 'p' bevatten doet er niet toe. Vergelijkbaar pakt de regex l$ alleen appel en sinaasappel:
$ egrep 'l$' fruit.txt
appel
sinaasappel
Denk om de quootjes! In de meeste shells heeft het dollarteken een speciale betekenis. Door enkele quootjes (geen dubbele quootjes of backticks (`)) om de regex te zetten wordt de regex bij wijze van spreken beschermd tegen de shell. Het is in het algemeen wel een goed idee om enkele quootjes om je regex te zetten, dus dat zal ik vanaf hier ook in de voorbeelden doen.
De draad weer oppakkend, ^kat$ pakt regels die exact kat bevatten. Op dezelfde manier kun je lege regels vinden met ^$. Als je het wat lastig vindt om dat in te zien, pas dan gewoon de definities toe. De regex zegt in feite: "Pas een begin-van-de-regel, gevolgd door een einde-van-de-regel". Da's inderdaad wel zo'n beetje wat een lege regel inhoudt, niet?
Bedenk wel, een regex met alleen een begin-van-de-regel anker ^ past altijd, aangezien elke regel een begin heeft. Hetzelfde geldt natuurlijk voor een einde-van-de-regel anker. Als je me niet gelooft, probeer het dan maar uit op de fruitlijst:
$ egrep '^' fruit.txt
appel
sinaasappel
peer
perzik
druif
banaan
bosbes
pruim
Een boel regex implementaties bieden de mogelijkheid om woordankers te gebruiken. Zoals je kon zien vindt een regex als kat niet alleen het woord kat, maar ook alle gevallen waar kat verstopt zit in andere, langere woorden. In die gevallen kun je begin-van-woord en einde-van-woord ankers gebuiken, respectievelijk \< en \>. Deze metakarakters passen niet op karakters, maar ertussen.
Dus als je alleen op zoek bent naar gevallen van het woord kat, zou je de regex \<kat\> kunnen gebruiken.
Voor het volgende doe-voorbeeld heb je het katten.txt bestand nodig, met een aantal woorden waar kat in voorkomt. Probeer eerst het volgende:
$ egrep '\<kat' katten.txt
kat
kattevoer
katalogus
magere kat
Met dit voorbeeld wordt duidelijk dat start-van-woord grenzen niet alleen werken tussen woorden, maar ook aan het begin van de regel.
Deze woordgrensankers worden echter niet door alle regex-implementaties ondersteund. Een aantal implementaties (waaronder die van perl) biedt in plaats daarvan is-woord-grens en geen-woord-grens ankers, in welk geval de regex \<kat\> vervangen moet worden door \bkat\b.
In deze context dient het begrip "woord" licht opgevat te worden; elke combinatie van letters (boven- en onderkast), de underscore ( _ ) en cijfers telt als een woord wanneer je met woordgrensankers bezig bent.
Inhoudsopgave
- Inleiding
- Wat zijn het?
- Metakarakters
- Karakterklassen
- De Punt
- Kwantificeerders
- Alternatie
- Groeperen
- Terugverwijzingen
- Ten slotte