Nieuws
Nieuwe distributie
Onlangs zijn we overgestapt op een nieuwe Linux-distributie, nl. Pardus Linux
Dit lijkt ons een prima distributie, zowel voor beginners als experts.
|
|
16. Reguliere Expressies
Een reguliere expressie is een soort formule om een bepaalde reeks tekens in een tekst te vinden. Net zoals
jokertekens, maar dan met veel meer mogelijkheden. Veel (Linux-) programma's kunnen werken met reguliere
expressies, bv. vi, grep, sed, perl, enz.
Veel mensen komen er niet toe om ze te gebruiken, omdat ze ingewikkeld lijken. Maar met wat oefening kunnen
ze het leven van een computer-gebruiker heel wat aangenamer maken, omdat ze je heel wat routinewerk uit handen
kunnen nemen.
Reguliere expressies zijn (meestal) samengesteld uit "gewone" tekens en zgn. metacharacters.
Gewone tekens bevatten (hoofd- en kleine-) letters en/of cijfers. Metacharacters hebben een speciale
betekenis, die we straks zullen beschrijven.
De eenvoudigste toepassing van een reguliere expressie ziet eruit als een normale string (een
string is een rijtje, of slechts één, "gewone" tekens). Zo bevat de reguliere expressie
boos geen metacharacters. Deze expressie zal op de woorden boos en boosaardig
passen, maar niet op bv. Boos (vanwege de hoofdletter...).
Maar om echt gebruik te kunnen maken van reguliere expressies, is het nodig om een goed begrip te hebben
van metacharacters. Hieronder staan ze op een rijtje:
| Metacharacter | Beschrijving |
| . |
Een enkel "gewoon" teken. De reguliere expressie r.t zal passen op bv.
rat, r t, rot en rit, maar niet op roet. |
| $ |
Betekent: het eind van een regel. De reguliere expressie haar$ zal passen
op de string Hij heeft weinig haar, maar niet op De kat verhaart. |
| ^ |
Betekent: het begin van een regel. Zo slaat de reguliere expressie ^hoe wel
op hoe en waarom, maar niet op waarom en hoe |
| * |
Zoekt naar het voorkomen van nul of meer keer het er direct aan voorafgaande teken.
Bv. betekent .* elke willekeurig aantal (dus ook nul) tekens. |
| \ |
Is een zgn. escape-character, bedoeld om van een metacharacter een gewoon teken te
maken. Stel, dat je in een tekst naar het dollar-teken zoekt, dan kun je niet de reguliere expressie
$ gebruiken, omdat dit een meta-character is, dus gebruik je \$, om aan te geven, dat
het je om het letterlijke $-teken gaat. |
| [ ] |
Past op elk teken, dat tussen de haken staat. De reguliere expressie r[aiu]t
zal passen op rat, rit en rut, maar niet op rot. Je kunt ook een
tekenreeks opgeven. Met [0-9] wordt bv. elk willekeurig cijfer bedoeld. Ook meerdere reeksen
zijn mogelijk: [A-Za-z] betekent: elke hoofd- of kleine letter. Om aan te geven, dat de tussen de
haken staande tekens juist niet gevonden moeten worden, gebruik je als eerste teken na de
openingshaak een ^. Bv.: [^029] zal passen bij elk teken, behalve bij de 0,
de 2 en de 9. |
| \< \> |
Betekent: het begin (\<) of het eind (\>) van een woord. Bv.
\<def past bij definitief, maar niet bij gedefinieerd.
Let op: dit meta-character wordt niet door elke toepassing ondersteund. |
| \( \) |
Behandelt de expressie tussen \( en \) als een groep en bewaart de
resultaten, die bij deze expressie passen in tijdelijke "buffers". Tot maximaal 9 bij de expressie
passende resultaten kunnen opgeslagen worden in die buffers. De buffers zijn op te roepen als
\1 t/m \9. Lijkt ingewikkeld, maar met de later volgende voorbeelden, wordt het wel
duidelijk. |
| | |
Betekent en/of. Bijvoorbeeld: (hem|haar) past bij de regels Het
is van hem en Het is van haar, maar niet bij Het is van hen.
Ook dit meta-character wordt niet door elke toepassing ondersteund. |
| + |
Zoekt naar het één of meer keer voorkomen van de direct aan het
+-teken voorafgaande teken of expressie. Bv.: de reguliere expressie 9+ past bij
9, 99 en bij 99999.
Ook dit meta-character wordt niet door elke toepassing ondersteund. |
| ? |
Past bij het 0 of 1 keer voorkomen van het teken of de expressie die direct aan het
?-teken vooraf gaat.
Ook dit meta-character wordt niet door elke toepassing ondersteund. |
\{i\} \{i,j\} |
De betekenis hiervan is het best duidelijk te maken met een voorbeeld:
A[0-9]\{3\} zal passen bij A gevolgd door precies 3 cijfers, bv. A572, dus
niet bij A9836, want hier staan 4 cijfers achter de A.
De expressie [0-9]\{4,6\} bekent het voorkomen van precies 4, 5 of 6 cijfers.
De expressie [0-9]\{3,\} betekent het voorkomen van 3 of meer cijfers.
Ook dit meta-character wordt niet door elke toepassing ondersteund. |
Zoals bij een aantal meta-characters al wordt aangegeven, werken ze niet allemaal bij elke toepassing. Dat
komt omdat er meerdere "dialecten" van reguliere expressies bestaan. Zo zal het laatste in bovenstaande
tabel genoemde meta-character (\{i\} prima werken bij grep, maar het meta-character
+ doet het daar niet, maar wel weer bij vi.
In de man-pages van de diverse toepassingen is vaak terug te vinden, welk dialect de betreffende toepassing
"spreekt".
Toch hieronder nog even een tabel met een overzicht van welke meta-characters door welke toepassingen
ondersteund worden (aangegeven met een "X"). De hier niet genoemde meta-characters doen het in alle
genoemde toepassingen.
| Toepassing | \( \) | \{ \} | ? |
+ | | | ( ) |
| vi, fgrep | X | - | - | - | - | - |
| awk | - | - | X | X | X | X |
| sed, ex, grep | X | X | - | - | - | - |
| Tcl, egrep, perl | X | - | X |
X | X | X |
Voorbeelden
We kunnen de werking van reguliere expressies het best verduidelijken met voorbeelden, waarbij dan ook nog
het e.e.a. verteld kan worden over de toepassing, die we erbij gebruiken. Laten we beginnen met
vi:
vi
Een mogelijkheid van vi, die we niet in het artikel over vi besproken hebben, is het
vervangen van tekst. Dit wordt gedaan vanuit de "dubbele punt-mode" (geef een escape om in de
opdracht-mode te komen en type daar een dubbele punt (:)).
De vervangingsopdracht ziet er (vauit de opdracht-mode) als volgt uit:
:bereiks/patroon1/patroon2/g
De dubbele punt brengt je in de zgn.ex-mode. De hierna gegeven opdrachten hebben betrekking op het
bestand, dat op dat moment bewerkt wordt.
bereik specificeert voor welke regels de opdracht geldt. Het procent-teken (%) geeft aan,
dat het om alle regels gaat. Het dollar-teken ($) betekent: alleen de laatste regel.Je kunt ook
zelf de regels specificeren, bv. 10, 20 betekent: regels 10-20; .,$ betekent: van de
huidige regel tot de laatste; .+2, $-5 betekent: vanaf 2 regels na de huidige tot de vijfde regel
boven de laatste.
s is de vervangings-opdracht.
patroon1 is de reguliere expressie, waarnaar gezocht wordt.
patroon2 is de "tekst", die als vervanging dient.
g is optioneel. Als je hem vermeldt, zal de vervanging gebeuren in alle aangegeven regels. Als je
hem niet vermeldt, zal de vervanging alleen gebeuren bij de eerste keer, dat patroon1 gevonden
wordt.
Voorbeelden:
Probeer ze met de hiervoor gegeven informatie voor jezelf uit te leggen!
| :%s/ */ /g | Vervangt 1 of meer spaties achter elkaar door een enkele
spatie. |
| :%s/ *$// | Verwijdert alle spaties aan het eind van de regel. |
| :%s/^/ /g | Voegt een spatie in aan het begin van iedere regel. |
| :%s/^[0-9][0-9]* // | Verwijdert alle nummers van het begin van de regel. |
| :%s/p[aeio]t/put/g | Vervangt overal waar pat, pet, pit
of pot voorkomt, deze in put |
| :%s/t\([aou]\)g/h1t/g | Vervangt elke tag, tog en tug
door resp. hat, hot en hut |
Het laatste voorbeeld hierboven is het lastigst: het maakt gebruik van \( \) en de buffer
(\1).
sed
Ook hiervoor enkele voorbeelden:
| sed 's/^$/d' tekst.txt | Verwijdert alle lege regels. |
| sed 's/^[ \t]*$/d' tekst.txt | Verwijdert alle regels, die alleen witruimte (spaties
en tabs) bevatten. |
| sed 's/"//g' tekst.txt | Verwijdert alle (dubbele) aanhalingstekens
(") |
Lees eventueel de man-pages van sed nog eens door of kijk nog eens naar het artikel over
tekstgereedschappen om te begrijpen wat er in deze voorbeelden gebeurt.
grep
Dit is een opdracht, die eigenlijk gemaakt is om te werken met reguliere expressies. De afkorting
grep betekent Global Regular Expression Print. Lees, om de voorbeelden te kunnen
begrijpen eventueel de man-pages en/of het artikel over tekstgereedschappen nog eens door.
We gaan bij de hieronder genoemde voorbeelden uit van een bestand, genaamd tel.txt, dat een lijst
bevat, met op elke regel een naam, gevolgd door een komma, dan de voornaam, gevolgd door een tab
met daarna een (huis-)telefoonnummer:
Francis, John 5-3871
Wong, Fred 4-4123
Jones, Thomas 1-4122
Salazar, Richard 5-2522
| grep '\t5-...1' tel.txt | Geeft alle telefoonnummers uit tel.txt
weer, die beginnen met een 5 en eindigen met een 1. De tab wordt aangegeven met
\t. |
| grep '^s[^ ]* R' tel.txt | Geeft alle regels weer, waarvan de achternaam begint met
een S en de voornaam met een R. |
| grep '^[JW]' tel.txt | Geeft alle regels weer, waarvan de achternaam begint met een
J of een W. |
| grep '^[M-Z].*[12]' tel.txt | Geeft alle regels weer, waarvan de achternaam begint
met een letter uit de rij M t/m Z en waarvan het telefoonnummer eindigt op een
1 of een 2. |
Slot
En hiermee eindigt het artikel over reguliere expressies. Het omgaan met deze materie is vooral een kwestie
van veel oefenen. Misschien kun je er een sport van maken om allerlei problemen op te zoeken, die wellicht
zijn op te lossen met reguliere expressies, zoals bijvoorbeeld:
- Het controleren van een email-adres.
- Het verwijderen van HTML-tags uit een tekst.
- Het omwisselen van 2 kolommen in een tabel.
- Enz., enz.
Want, zoals bij zoveel zaken: oefening baart kunst!.
Laatst herzien op 18-12-2006
|