Cursus
Het concept van reguliere expressies, meestal regex genoemd, bestaat in veel programmeertalen, zoals R, Python, C, C++, Perl, Java en JavaScript. Je kunt de functionaliteit van regex gebruiken in de basistaal of via libraries. Voor de meeste programmeertalen is de syntaxis van regex-patronen vergelijkbaar.
In deze tutorial bekijken we wat reguliere expressies in R zijn, waarom ze belangrijk zijn, welke tools en functies ons helpen ermee te werken, welke regex-patronen het meest voorkomen en hoe je ze gebruikt. Tot slot overlopen we enkele geavanceerde toepassingen van R-regex.
Wat zijn R-regex en waarom zou je ze gebruiken?
Een reguliere expressie, regex, in R is een reeks tekens (of zelfs één teken) die een bepaald patroon in een tekst beschrijft. Regex-patronen kunnen zo kort zijn als ‘a’ of zo lang als die in deze StackOverflow-thread.
Grofweg geldt bovenstaande definitie van regex niet alleen voor R, maar voor elke programmeertaal die reguliere expressies ondersteunt.
Regex is een zeer flexibel en krachtig hulpmiddel dat veel wordt gebruikt voor het verwerken en ontginnen van ongestructureerde tekstdata. Zo vinden ze toepassing in zoekmachines, lexicale analyse, spamfiltering en teksteditors.
Tools en functies om met R-regex te werken
Hoewel regex-patronen voor de meeste programmeertalen vergelijkbaar zijn, verschillen de functies om ermee te werken.
In R kunnen we de functies van base R gebruiken om regex te detecteren, matchen, lokaliseren, extraheren en vervangen. Hieronder staan de belangrijkste functies die zoeken naar regex-overeenkomsten in een karaktervector en vervolgens het volgende doen:
-
grep(),grepl()– geven de indexen terug van strings met een overeenkomst (grep()) of een logische vector die aangeeft welke strings een overeenkomst bevatten (grepl()). -
regexpr(),gregexpr()– geven per string de index terug waar de overeenkomst begint en de lengte daarvan. Terwijlregexpr()deze informatie alleen geeft voor de eerste overeenkomst (van links), doetgregexpr()dit voor alle overeenkomsten. -
sub(),gsub()– vervangen een gedetecteerde overeenkomst in elke string door een opgegeven string (sub()– alleen voor de eerste overeenkomst,gsub()– voor alle overeenkomsten). -
regexec()– werkt alsregexpr()maar geeft dezelfde informatie ook voor een opgegeven subexpressie binnen de overeenkomst. -
regmatches()– werkt alsregexec()maar geeft de exacte strings terug die zijn gedetecteerd voor de totale overeenkomst en een opgegeven subexpressie.
Maar in plaats van de native R-functies te gebruiken, is een handigere en consistentere manier om met R-regex te werken het gebruik van het gespecialiseerde stringr-pakket uit de tidyverse-collectie. Deze library is gebouwd bovenop het stringi-pakket. In de stringr-library beginnen alle functies met str_ en hebben ze veel intuïtievere namen (net als de namen van hun optionele parameters) dan die van base R.
Om het stringr-pakket te installeren en te laden, voer je het volgende uit:
install.packages('stringr')
library(stringr)
De onderstaande tabel toont de overeenkomst tussen de stringr-functies en die van base R die we eerder in deze sectie bespraken:
|
stringr |
Base R |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Een volledige lijst van de stringr-functies en reguliere expressies vind je in deze cheat sheets, maar we bespreken er een aantal verderop in deze tutorial.
Let op: in de stringr-functies geven we eerst de data door en daarna een regex, terwijl dit in de base R-functies precies andersom is.
Nog een opmerking: Deze tutorial gebruikt stringr 1.5.1, de huidige versie in 2026. Gebruik je een oudere versie, dan kan bepaald gedrag afwijken — vooral rond str_view(), dat in 1.5.0 aanzienlijk is vernieuwd.
R-regexpatronen
We gaan nu de meest gebruikte R-regexpatronen en hun gebruik overlopen en tegelijk enkele stringr-functies oefenen.
Voor we dat doen, kijken we naar een heel eenvoudig voorbeeld. Namelijk: heeft een unicorn minstens één corn? 😉
str_detect('unicorn', 'corn')
Output:
TRUE
In dit voorbeeld gebruikten we de str_detect()-functie van stringr om de aanwezigheid van de string corn in de string unicorn te controleren.
Meestal zoeken we echter niet naar een letterlijke string in een tekst, maar naar een bepaald patroon – een reguliere expressie. Laten we dergelijke patronen verkennen.
Escapes voor tekens
Er zijn een paar tekens met een speciale betekenis in R-reguliere expressies. Preciezer gezegd: ze matchen niet zichzelf, zoals letters en cijfers wel doen, maar doen iets anders:
str_extract_all('unicorn', '.')
Output:
1. 'u' 'n' 'i' 'c' 'o' 'r' 'n'
We zien duidelijk dat er geen punten in onze unicorn staan. Toch extraheerde de functie str_extract_all() elk afzonderlijk teken uit deze string. Dat is precies de taak van het teken . – een willekeurig enkel teken matchen, behalve een regeleinde.
Wat als we een letterlijke punt willen extraheren? Daarvoor moeten we een regex-escape vóór de punt gebruiken – een backslash (\). Let wel op een valkuil: een backslash wordt ook in strings zelf als escape-teken gebruikt. Dat betekent dat we eerst het escape-teken moeten “escapen” door een dubbele backslash te gebruiken. Zo werkt het:
str_extract_all('Eat. Pray. Love.', '\\.')
Output:
1. '.' '.' '.'
De backslash helpt dus de speciale betekenis op te heffen van sommige symbolen in R-reguliere expressies en ze letterlijk te interpreteren. Het heeft ook de omgekeerde taak: een speciale betekenis geven aan sommige tekens die anders letterlijk geïnterpreteerd zouden worden. Hieronder staat een tabel met de meest gebruikte escape-sequenties:
|
R-regex |
Wat matcht |
|
|
Een woordgrens (een grens tussen een |
|
|
Geen woordgrens ( |
|
|
Een regeleinde |
|
|
Een tab |
|
|
Een verticale tab |
We bekijken enkele voorbeelden en houden in het achterhoofd dat we ook hier een dubbele backslash moeten gebruiken. Tegelijk introduceren we nog een stringr-functie: str_view() om de HTML-weergave van de eerste of alle matches te bekijken:
str_view('Unicorns are so cute!', 's\\b')
str_view('Unicorns are so cute!', 's\\B')
Output:
Unicorns are so cute!
Unicorns are so cute!
In de string Unicorns are so cute! komen twee s’en voor. Bovenaan lichtte het eerste R-regexpatroon de eerste s uit (omdat er een spatie op volgt), terwijl het tweede patroon – de tweede instantie (omdat er een andere letter op volgt, geen woordgrens).
Nog een paar voorbeelden:
cat('Unicorns are\nso cute!')
str_view('Unicorns are\nso cute!', '\\n')
Output:
Unicorns are
so cute!
Unicorns are_so cute!
cat('Unicorns are\tso cute!')
str_view('Unicorns are\tso cute!', '\\t')
Output:
Unicorns are so cute!
Unicorns are_so cute!
Tekenklassen
Een tekenklasse matcht elk teken uit een vooraf gedefinieerde set tekens. Ingebouwde tekenklassen hebben dezelfde syntaxis als de escape-sequenties die we in de vorige sectie zagen: een backslash gevolgd door een letter waaraan hij een speciale betekenis geeft in plaats van een letterlijke. De populairste constructies staan hieronder:
|
R-regex |
Wat matcht |
|
|
Elk woordteken (een letter, cijfer of underscore) |
|
|
Elk niet-woordteken |
|
|
Elk cijfer |
|
|
Elk niet-cijfer |
|
|
Elk spatie-teken (een spatie, een tab, een regeleinde, enz.) |
|
|
Elk niet-spatie-teken |
Enkele voor de hand liggende voorbeelden:
str_view('Unicorns are so cute!', '\\w')
str_view('Unicorns are so cute!', '\\W')
Output:
[1] │ <U><n><i><c><o><r><n><s>< ><a><r><e>< ><s><o>< ><c><u><t><e>!
[1] │ Unicorns< >are< >so< >cute<!>
str_view('Unicorns are\nso cute!', '\\s')
str_view('Unicorns are\nso cute!', '\\S')
Output:
Unicorns are<\n>so cute!
str_detect('Unicorns are so cute!', '\\d')
Output:
FALSE
Ingebouwde tekenklassen kunnen ook in een alternatieve vorm voorkomen – [:character_class_name:]. Sommige van deze tekenklassen hebben een equivalent met een backslash; andere niet. De meest gebruikelijke zijn:
|
R-regex |
Wat matcht |
|
|
Elke letter |
|
|
Elke kleine letter |
|
|
Elke hoofdletter |
|
|
Elk cijfer (equivalent aan |
|
|
Elke letter of elk cijfer |
|
|
Elk hexadecimaal cijfer |
|
|
Elk leesteken |
|
|
Elke letter, elk cijfer of leesteken |
|
|
Een spatie, tab, regeleinde, enz. (equivalent aan |
Laten we enkele voorbeelden bekijken en onthouden dat we deze R-regexpatronen tussen rechte haken moeten plaatsen:
str_view('Unicorns are so cute!', '[[:upper:]]')
str_view('Unicorns are so cute!', '[[:lower:]]')
Output:
Unicorns are so cute!
Unicorns are so cute!
str_detect('Unicorns are so cute!', '[[:digit:]]')
Output:
FALSE
str_extract_all('Unicorns are so cute!', '[[:punct:]]')
Output:
1. '!'
str_view('Unicorns are so cute!', '[[:space:]]')
Output:
Unicorns_are_so_cute!
Je kunt ook een zelfgedefinieerde tekenklasse maken door tussen rechte haken elke set tekens te plaatsen waarvan je elk afzonderlijk teken wilt matchen. Je kunt een bereik van letters of cijfers (in Unicode-volgorde) opnemen, meerdere verschillende bereiken, of elke sequentiële of niet-sequentiële set van tekens of groepen tekens.
Bijvoorbeeld, [A-D] matcht elke hoofdletter van A tot en met D, [k-r] – elke kleine letter van k tot en met r, [0-7] – elk cijfer van 0 tot en met 7, en [aou14%9] – elk van de tekens binnen de rechte haken. Als we het dakje (^) als eerste teken binnen de haken plaatsen, zal ons R-regexpatroon alles behalve de opgegeven tekens matchen. Let op dat bovenstaande matchmechanismen hoofdlettergevoelig zijn.
str_view('Unicorns Are SOOO Cute!', '[O-V]')
str_view('Unicorns Are SOOO Cute!', '[^O-V]')
Output:
Unicorns Are SOOO Cute!
Unicorns Are SOOO Cute!
str_view('3.14159265359', '[0-2]')
Output:
3.14159265359
str_view('The number pi is equal to 3.14159265359', '[n2e9&]')
Output:
The number pi is equal to 3.14159265359
Kwantoren
Vaak moeten we een bepaald R-regexpatroon herhaaldelijk matchen, in plaats van precies één keer. Daarvoor gebruiken we kwantoren. Een kwantor komt altijd na het regex-patroon waarop hij betrekking heeft. De meest voorkomende kwantoren staan in de tabel hieronder:
|
R-regex |
Aantal patroonherhalingen |
|
|
0 of meer |
|
|
minstens 1 |
|
|
maximaal 1 |
|
|
exact n |
|
|
minstens n |
|
|
minstens n en maximaal m |
Laten we ze allemaal uitproberen:
str_extract('dog', 'dog\\d*')
Output:
'dog'
We kregen de oorspronkelijke string dog: er staan geen cijfers aan het einde van die string, maar dat is oké (0 of meer cijfers).
str_extract('12345', '\\d+')
Output:
'12345'
str_extract('12345', '\\d?')
Output:
'1'
str_extract('12345', '\\d{3}')
Output:
'123'
str_extract('12345', '\\d{7,}')
Output:
NA
We kregen NA omdat we niet minstens 7 cijfers in de string hebben, slechts 5.
str_extract('12345', '\\d{2,4}')
Output:
'1234'
Ankers
Standaard matcht R-regex elk deel van een opgegeven string. We kunnen dit gedrag wijzigen door een bepaalde positie van een R-regexpatroon in de string te specificeren. Meestal willen we matchen vanaf het begin of het einde van de string. Daarvoor gebruiken we de twee belangrijkste ankers in R-reguliere expressies:
-
^– matcht vanaf het begin van de string (bij multiregel-strings – het begin van elke regel) -
$– matcht vanaf het einde van de string (bij multiregel-strings – het einde van elke regel)
Zo werken ze op het voorbeeld van een palindroom stella won no wallets:
str_view('stella won no wallets', '^s')
str_view('stella won no wallets', 's$')
Output:
<s>tella won no wallets
stella won no wallet<s>
Als we de tekens ^ of $ zelf willen matchen, moeten we het betreffende teken vooraf laten gaan door een backslash (dubbel):
str_view('Do not have 100$, have 100 friends', '\\$')
Output:
Do not have 100$, have 100 friends
Het is ook mogelijk om te ankeren op woord- of niet-woordgrenzen binnen de string (\b en \B respectievelijk):
str_view('road cocoa oasis oak boa coach', '\\boa')
str_view('road cocoa oasis oak boa coach', 'oa\\b')
str_view('road cocoa oasis oak boa coach', 'oa\\B')
Output:
road cocoa oasis oak boa coach
road cocoa oasis oak boa coach
road cocoa oasis oak boa coach
Boven matchten we de lettercombinatie oa:
- 1e voorbeeld – aan het begin van woorden
- 2e voorbeeld – aan het einde van woorden
- 3e voorbeeld – wanneer die gevolgd wordt door een woordteken (in ons geval – door een letter)
Alternatie
Met de alternatie-operator (|) kunnen we meer dan één R-regexpatroon in dezelfde string matchen. Let op: als we deze operator gebruiken binnen een zelfgedefinieerde tekenklasse, wordt hij letterlijk geïnterpreteerd en voert dus geen alternatie uit.
str_view('coach koala board oak cocoa road boa load coat oasis boat', 'boa|coa')
Output:
coach koala board oak cocoa road boa load coat oasis boat
In het bovenstaande voorbeeld matchten we alle instanties van boa of coa.
Groepering
R-regexpatronen volgen bepaalde voorrangsregels. Bijvoorbeeld, herhaling (met kwantoren) heeft voorrang op ankers, terwijl ankers weer voorrang hebben op alternatie. Om deze regels te omzeilen en de voorrang van een bepaalde bewerking te verhogen, gebruiken we groepering. Dit doen we door een subexpressie van interesse tussen ronde haken te plaatsen.
Groepering werkt het best in combinatie met de alternatie-operator. De onderstaande voorbeelden tonen duidelijk het effect van zo’n combinatie:
str_view('code rat coat cot cat', 'co|at')
str_view('code rat coat cot cat', 'c(o|a)t')
Output:
code rat coat cot cat
code rat coat cot cat
Geavanceerde toepassingen van R-reguliere expressies
Alles wat we tot nu toe hebben besproken, geeft ons een goede basis om te beginnen werken met R-reguliere expressies. Maar er is nog veel meer mogelijk met dit krachtige hulpmiddel. Zonder in details te treden, noemen we enkele geavanceerde bewerkingen die we met R-regex kunnen uitvoeren:
- Standaardinstellingen van stringr-functies overschrijven
- Grapheemclusters matchen
- Backreferencing van groepen
- Unicode-eigenschappen matchen
- Geavanceerd escapen van tekens toepassen
- Controleren op het bestaan van een patroon zonder het in de output op te nemen (zogenaamde lookarounds)
- Het herhalingsmechanisme lui maken in plaats van gulzig
- Werken met atomaire groepen
Leer meer in onze cursus Intermediate Regular Expressions in R.
R-regexuitdaging
Nu ben jij aan de beurt om de R-regexpatronen uit deze tutorial te oefenen. Gebruik daarvoor onze Dataset: Internet News and Consumer Engagement, en probeer het volgende: extraheer de topniveaudomeinen (TLD’s) uit alle URL’s. Enkele voorbeelden van TLD’s zijn com, net, uk, enz.
Er zijn meerdere manieren om deze taak te volbrengen, waaronder elegante en compacte one-liners (hint: je kunt meer leren over lookarounds in R-regex, genoemd in de vorige sectie, en die gebruiken om dit probleem op te lossen). Overweeg de volgende zeer losse leidraad voor een relatief “rookie”-aanpak:
- Inspecteer enkele URL’s in de dataset en kijk welke patronen altijd in elke URL vóór de TLD staan en welke optioneel zijn
- Kijk of er verplichte patronen in een URL ná de TLD staan (en zo ja, welke) en welke patronen optioneel zijn
- Verwijder alles vóór de TLD van de URL
- Verwijder alles ná de TLD van de URL
Om het probleem met bovenstaand algoritme op te lossen, hoef je niets extra’s te doen of te leren. Herhaal gewoon wat we in deze tutorial hebben besproken en zet je kennis om in de praktijk. Je hebt met name de stringr-functies, escapes, tekenklassen, kwantoren en groepering nodig.
Bonus: uitdaging #2
Wil je meer oefenen, dit keer zonder hints, probeer dan het volgende: gebruik dezelfde dataset uit de vorige uitdaging en extraheer de domeinnamen uit alle URL’s. Een voorbeeld van een domeinnaam is google in de URL www.google.com.
Conclusie
Samenvattend hebben we in deze tutorial veel geleerd over R-reguliere expressies. We bespraken onder meer:
- Wat R-regex zijn
- Waarom ze belangrijk zijn en waar ze worden toegepast
- Welke functies (zowel uit native R als een gespecialiseerd pakket) worden gebruikt om met R-reguliere expressies te werken
- De meest voorkomende R-regexpatronen en hun reikwijdte, nuances en valkuilen
- Wanneer en hoe je escapes, tekenklassen, kwantoren, ankers, alternatie en groepering met R-regex gebruikt
- Diverse voorbeelden van het toepassen van R-regex en functies
- Enkele geavanceerde bewerkingen met R-reguliere expressies
Deze vaardigheden en concepten helpen je bij het werken in R en in veel andere programmeertalen, omdat het concept van reguliere expressies voor al die talen hetzelfde is en de syntaxis van regex voor de meeste ervan vrij vergelijkbaar is.
Als je je R-vaardigheden wilt uitdiepen, bekijk dan de volgende cursussen, skill tracks en artikelen van DataCamp:
IBM Certified Data Scientist (2020), eerder petroleumgeoloog/geomodelleur voor olie- en gasvelden wereldwijd, met 12+ jaar internationale werkervaring. Vaardig in Python, R en SQL. Expertisegebieden: datacleaning, datamanipulatie, datavisualisatie, data-analyse, datamodellering, statistiek, storytelling, machine learning. Ruime ervaring met het beheren van datascience-communities en het schrijven/reviewen van artikelen en tutorials over data science en carrière-onderwerpen.
FAQs
Hoe controleer ik welke versie van stringr ik heb, en hoe update ik die?
Voer dit uit in je R-console:
packageVersion('stringr')
Als het iets onder 1.5.0 toont, update dan met:
install.packages('stringr')
Zal str_view_all() ooit helemaal stoppen met werken, of is het veilig om het voorlopig te blijven gebruiken?
Het werkt nog steeds in de huidige versie van stringr en zal dat nog een tijd blijven doen — deprecatie in R betekent niet dat iets meteen wordt verwijderd. Elke aanroep geeft echter een waarschuwing, en dat wordt snel lawaaierig. Belangrijker: verouderde functies worden uiteindelijk verwijderd in toekomstige major-releases, dus code die afhankelijk is van str_view_all() zal uiteindelijk breken. Het kost zo’n 30 seconden om te fixen, dus beter nu dan later.
Waarom moet ik in R-regex een dubbele backslash (\\) gebruiken terwijl andere talen er maar één gebruiken?
A: Omdat R de string verwerkt vóórdat die naar de regex-engine gaat. Een enkele \ wordt geconsumeerd door R’s stringparser, dus je hebt \\ nodig om ervoor te zorgen dat één \ de regex-engine bereikt. Schrijf \\d en R zet het om naar \d voor de regex — schrijf je \d dan gaat het stuk voordat de regex het ooit ziet.
Wat is het verschil tussen grep() en grepl() in base R, en welke moet ik gebruiken?
grep() geeft de indexen van overeenkomende elementen; grepl() geeft een TRUE/FALSE-vector terug met dezelfde lengte als je input. Gebruik grep() wanneer je posities nodig hebt, grepl() wanneer je wilt filteren of testen. In de praktijk zijn de stringr-equivalenten str_subset() en str_detect() voor de meeste use-cases netter.
Wanneer gebruik ik een tekenklasse zoals [aeiou] versus alternatie zoals a|e|i|o|u?
Voor enkele tekens gebruik je altijd een tekenklasse — dat is sneller en schoner. Gebruik alternatie met | wanneer een van je opties uit meer dan één teken bestaat, zoals cat|dog, want die kunnen niet binnen [].
Wat is het verschil tussen de kwantoren *, + en ?
* = nul of meer (patroon is optioneel en kan herhalen). + = één of meer (minstens één vereist). ? = nul of één (optioneel, herhaalt niet). Ezelsbrug: + voegt toe (vereist minstens één), ? vraagt (misschien wel, misschien niet), * betekent vrij spel.
Wat is het verschil tussen sub() en gsub(), en wat zijn hun stringr-equivalenten?
sub() vervangt alleen de eerste match; gsub() vervangt alle matches. Hun stringr-equivalenten zijn str_replace() en str_replace_all(). De stringr-versies hebben de voorkeur omdat ze de tidyverse-argumentvolgorde volgen — eerst data, dan patroon, dan vervanging.
Wanneer gebruik ik regexpr() versus gregexpr() in base R?
regexpr() vindt de positie van de eerste match in elke string; gregexpr() vindt alle matches. De meeste R-gebruikers geven de voorkeur aan stringr’s str_locate() en str_locate_all() — die geven resultaten terug als nette data frames met kolommen start en end in plaats van het onhandige formaat van base R met benoemde integers.
Wat betekent ^ tussen rechte haken versus erbuiten?
Buiten [] anker je aan het begin van een string: ^Hello matcht strings die beginnen met "Hello". Binnen [] als eerste teken, negeert het de set: [^aeiou] matcht alles wat geen klinker is. Overal anders binnen [] wordt het als een letterlijke dakje behandeld.
Wanneer gebruik ik \b-woordgrenzen in plaats van ^- en $-ankers?
Gebruik \b wanneer je een heel woord ergens in een string wilt matchen, niet alleen aan het begin of eind. Zoeken naar cat matcht ook “concatenated” — \bcat\b matcht alleen het losse woord. Dit is vooral handig bij tekstanalyse wanneer partiële matches je resultaten zouden vertekenen.

