Regex cheat sheet: metakarakters, groepen en lookarounds (volledige referentie)
Een reguliere expressie is een compacte patroontaal voor het matchen van tekst. \d+ betekent “een of meer cijfers”, ^Error betekent “een regel die met Error begint”. Veel meer is het niet. Deze regex cheat sheet zet de syntax op één scrollbare pagina: metakarakters, quantifiers, ankers, groepen, lookarounds en flags, plus 15+ patronen die je vandaag in JavaScript of Python kunt plakken.
Hij is geschreven voor developers die al weten wat een string is en een referentie willen, geen rondleiding. Spring naar de Quick reference-tabel als je alleen de symbolen nodig hebt. De secties over lookaround en valkuilen staan er voor het moment dat een regex ooit een server van je heeft platgelegd.
1. Wat is regex en waarom je het in 2026 nog steeds nodig hebt
Een regex is een patroon dat gecompileerd wordt tot een toestandsmachine, die een string scant en óf matcht óf faalt. De grammatica is klein, het toepassingsgebied niet.
AI kan een patroon voor je schetsen, maar een paar taken blijven gewoon mensenwerk wanneer je zelf regex schrijft.
- Logs uitlezen. Je hebt tien miljoen regels
nginx-access logs en je wilt elk 5xx-verzoek van een specifieke user agent. Een regex van 40 tekens viagrep -Eis in seconden klaar; een LLM-call per regel niet. - Form- en veldvalidatie. Telefoonnummers, postcodes, ISO-timestamps, licentiesleutels. Het patroon staat naast de input en draait in de browser op elke toetsaanslag.
- Bulk find-and-replace. Een refactor over duizend bestanden waarbij je een naam wilt capturen en weer wilt invoegen.
sed,ripgrepen de “Replace in files” van je editor spreken regex native.
Voor de JSON-helft van dezelfde toolbox is er ons jq spiekbriefje.
1.1 Hoe je een regex-patroon leest (5 seconden reguliere-expressietutorial)
De meeste patronen lees je het makkelijkst van links naar rechts, token voor token. Neem ^[A-Z]\w+\d{2,4}$ als voorbeeld:
^verankert de match aan het begin van de string.[A-Z]matcht precies één hoofdletter.\w+matcht één of meer woordtekens.\d{2,4}matcht tussen de twee en vier cijfers.$verankert aan het einde van de string.
De kunst zit in het lezen van eerst de ankers, dan de karakterklassen en daarna de quantifiers.
2. Quick reference-tabel
Voor de meeste lezers is dit de sectie waarvoor ze komen. Kopieer wat je nodig hebt.
Metakarakters
| Patroon | Matcht |
|---|---|
. | Elk teken behalve newline (of elk teken met de s/dotall-flag) |
\d | Een cijfer ([0-9], of alle Unicode-cijfers met de u-flag) |
\D | Een niet-cijfer |
\w | Een woordteken ([A-Za-z0-9_]) |
\W | Een niet-woordteken |
\s | Elke witruimte (spatie, tab, newline, …) |
\S | Elke niet-witruimte |
Quantifiers
| Patroon | Matcht |
|---|---|
* | 0 of meer (greedy) |
+ | 1 of meer (greedy) |
? | 0 of 1 (greedy) |
{n} | Precies n keer |
{n,m} | Tussen n en m keer |
{n,} | n of meer keer |
*?, +?, ??, {n,m}? | Lazy varianten van elke quantifier |
Ankers
| Patroon | Matcht |
|---|---|
^ | Begin van de string (of begin van de regel met m-flag) |
$ | Einde van de string (of einde van de regel met m-flag) |
\b | Woordgrens |
\B | Niet-woordgrens |
\A | Absoluut begin van de string (Python) |
\Z | Absoluut einde van de string (Python) |
Karakterklassen
| Patroon | Matcht |
|---|---|
[abc] | Een van a, b, c |
[^abc] | Alles behalve a, b, c |
[a-z] | Elke kleine letter |
[0-9] | Elk cijfer |
\p{L} | Elke Unicode-letter (u-flag in JS, standaard in Python re) |
Groepen
| Patroon | Matcht |
|---|---|
(...) | Capture-groep |
(?:...) | Niet-capturende groep |
(?<name>...) | Benoemde capture (JS ES2018+); Python gebruikt (?P<name>...) |
\1, \2 | Backreference naar groep 1, 2 |
Lookaround
| Patroon | Matcht |
|---|---|
(?=...) | Positieve lookahead |
(?!...) | Negatieve lookahead |
(?<=...) | Positieve lookbehind |
(?<!...) | Negatieve lookbehind |
Flags
| Flag | Effect |
|---|---|
i | Case-insensitive |
m | Multiline: ^ en $ matchen per regel |
s | Dotall: . matcht ook newlines |
g | Globaal (JS) — vind alle matches |
u | Unicode-modus |
y | Sticky (JS) — verankerd aan lastIndex |
3. Metakarakters en karakterklassen
3.1 Literals vs. speciale tekens
De meeste tekens zijn literal. De 12 metakarakters die je moet escapen wanneer je ze als zichzelf wilt gebruiken, zijn:
. ^ $ * + ? ( ) [ ] { } | \
. vergeten te escapen is veruit de meest voorkomende regex-bug. \. matcht een letterlijke punt. Binnen een karakterklasse matcht [.] ook een letterlijke punt. De meeste metakarakters verliezen hun werking binnen [...] behalve ], \, ^ (als eerste) en - (in het midden).
3.2 Karakter-shorthands
De shorthand-klassen ogen simpel, totdat Unicode opduikt:
// JavaScript — zonder de u-flag is \d alleen ASCII
/\d/.test('5'); // true
/\d/.test('٥'); // false (Arabisch-Indisch cijfer)
/\d/u.test('٥'); // false — zelfs met u blijft \d in JS ASCII
/\p{N}/u.test('٥'); // true — \p{N} is de Unicode-bewuste cijferklasse
# Python — de re-module behandelt \d standaard als Unicode
import re
re.match(r'\d', '٥') # <Match span=(0, 1)>
re.match(r'(?a)\d', '٥') # None — (?a) forceert ASCII
Als je alleen met Engelse ASCII-input werkt, zijn \d en [0-9] uitwisselbaar. Zodra een gebruiker een naam met een accent plakt, wil je \p{L} boven \w.
3.3 Eigen karakterklassen
// JavaScript
/[A-Za-z][A-Za-z0-9_-]{2,29}/.test('valid_handle-1'); // true
// Negatie en ranges gecombineerd
/[^aeiou\s]/g // elk teken dat geen klinker en geen witruimte is
Voor Unicode-categorieën is \p{L} “elke letter”, \p{N} “elk getal” en \p{Script=Han} “elk Han-teken”. JavaScript vereist de u-flag; Python ondersteunt \p{...} alleen via het regex-pakket van PyPI, niet via de stdlib re.
Werk je op de commandoregel, dan kom je ook POSIX-karakterklassen tegen:
| POSIX-klasse | Matcht | ASCII-equivalent |
|---|---|---|
[[:alpha:]] | letters | [A-Za-z] |
[[:digit:]] | cijfers | [0-9] (\d) |
[[:alnum:]] | letters + cijfers | [A-Za-z0-9] |
[[:space:]] | witruimte | \s |
[[:upper:]] | hoofdletters | [A-Z] |
[[:lower:]] | kleine letters | [a-z] |
POSIX-klassen werken in grep -E en sed -E. Ze werken niet in JavaScript of Python re — gebruik daar \d, \s en \w.
4. Quantifiers en greedy vs. lazy
4.1 Basis-quantifiers
/a*/.exec('aaab') // ['aaa'] — 0 of meer
/a+/.exec('aaab') // ['aaa'] — 1 of meer
/a?/.exec('aaab') // ['a'] — 0 of 1
/a{2,3}/.exec('aaaab') // ['aaa'] — 2 tot 3
4.2 Greedy vs. lazy
Standaard zijn quantifiers greedy. Ze pakken zoveel mogelijk en stappen pas terug om het hele patroon te laten passen. Plak een ? erachter en ze worden lazy.
const html = '<p>one</p><p>two</p>';
html.match(/<p>.*<\/p>/)[0]; // '<p>one</p><p>two</p>' (greedy slokt beide op)
html.match(/<p>.*?<\/p>/)[0]; // '<p>one</p>' (lazy stopt bij de eerste)
De lazy-variant is bijna altijd wat je wilt bij het extracten van tags of strings tussen aanhalingstekens. Een nog snellere route is . helemaal vermijden en een genegeerde klasse gebruiken: <p>[^<]*</p> is sneller dan <p>.*?</p> omdat er niets is om naar terug te backtracken.
4.3 Catastrofale backtracking
Op deze manier legt een regex een server plat. Nest een quantifier binnen een andere quantifier met ambigue overlap, en de engine verkent een exponentieel aantal paden voordat hij het opgeeft.
// Niet doen
/(a+)+b/.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!'); // duurt seconden
Bij 41 a’s gevolgd door ! probeert de engine ongeveer 2^41 splitspunten voordat hij besluit dat de b ontbreekt. Er zijn een paar manieren om eruit te komen:
- Plat het patroon af.
/a+b/doet hetzelfde werk zonder nesting. - Gebruik een atomic group (Python
regex, PCRE, Java, Ruby):(?>a+)+b. Zodraa+matcht, weigert de engine erin terug te backtracken. - Wissel van engine. Go’s
regexp, RE2 en deregex-crate van Rust gebruiken een lineaire NFA en kunnen by design niet catastrofaal backtracken.
JavaScript en Python re backtracken allebei en hebben geen atomic groups in de stdlib (het regex-pakket van Python voegt ze toe). Wanneer jij de lengte van de input controleert is dat prima. Komt de input van een gebruiker, valideer dan eerst de lengte of compileer tegen RE2.
5. Ankers en woordgrenzen
5.1 ^ en $
Standaard is ^ het begin van de hele input en $ het einde. Met de m-flag (multiline) worden het begin en einde van elke regel:
const log = 'INFO start\nERROR boom\nINFO done';
log.match(/^ERROR.*/); // null — single-line modus, ^ matcht alleen index 0
log.match(/^ERROR.*/m); // ['ERROR boom']
5.2 \b en \B
\b is een zero-width assertion: het matcht de positie tussen een woordteken (\w) en een niet-woordteken. Handig om op hele woorden te zoeken:
/\bcat\b/.test('the cat sat'); // true
/\bcat\b/.test('concatenate'); // false
Woordgrenzen worden gedefinieerd op \w, en dat is standaard ASCII. Chinese, Japanse en Koreaanse tekst kent geen spaties tussen woorden, dus \b detecteert daar geen woordgrenzen. Je hebt eerst een tokenizer nodig (jieba, MeCab), niet in plaats van regex maar ervóór.
5.3 Multiline-modus
import re
text = "INFO ok\nERROR fail\nINFO done\n"
re.findall(r'^ERROR.*$', text) # []
re.findall(r'^ERROR.*$', text, re.MULTILINE) # ['ERROR fail']
In JavaScript leest hetzelfde als text.match(/^ERROR.*$/gm). Combineer m met g om elke matchende regel te pakken.
6. Groepen, captures en backreferences
6.1 Capturende groepen
Haakjes hebben twee taken: ze groeperen subpatronen voor quantifiers, en ze capturen de match voor later gebruik.
'2026-05-13'.match(/(\d{4})-(\d{2})-(\d{2})/);
// ['2026-05-13', '2026', '05', '13', index: 0, ...]
Groepen worden van links naar rechts genummerd op basis van hun openings-haakje, beginnend bij 1.
6.2 Niet-capturende groepen
Wil je alleen groeperen en niet capturen, gebruik dan (?:...). Dat is sneller en houdt de genummerde groepen overzichtelijk:
/(?:https?):\/\/(\S+)/.exec('see https://go-tools.org');
// ['https://go-tools.org', 'go-tools.org']
// — het protocol wordt gegroepeerd maar niet gecaptured; groep 1 is de host
6.3 Benoemde groepen
Groepen een naam geven maakt patronen leesbaar en refactor-bestendig.
// JavaScript (ES2018+)
const m = '2026-05-13'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
m.groups.year; // '2026'
# Python — let op de (?P<...>) syntax
import re
m = re.match(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', '2026-05-13')
m.group('year') # '2026'
6.4 Backreferences
Met backreferences kun je een later deel van het patroon laten herhalen wat een eerdere capture matchte.
// Vind elk teken dat zich direct herhaalt
'bookkeeper'.match(/(\w)\1/g); // ['oo', 'kk', 'ee']
// Match gepaarde HTML-tags op naam
const tag = /<(\w+)>(.*?)<\/\1>/;
'<b>bold</b>'.match(tag);
// ['<b>bold</b>', 'b', 'bold']
In Python werkt \1 zowel in het patroon als in de vervanging; benoemde references zijn (?P=name) in het patroon en \g<name> in re.sub-vervangingen.
7. Lookarounds: lookahead en lookbehind
Lookarounds zijn zero-width assertions. Ze controleren een voorwaarde zonder tekens te consumeren, dus je kunt ze aan elkaar koppelen.
7.1 Lookahead
// Wachtwoord: minimaal 8 tekens, één cijfer, één hoofdletter, één kleine letter
const strong = /^(?=.*\d)(?=.*[A-Z])(?=.*[a-z]).{8,}$/;
strong.test('Hunter2!'); // true
strong.test('hunter2!'); // false — geen hoofdletter
// Negatieve lookahead — bestandsnamen die geen .tmp zijn
/^[\w-]+(?!\.tmp$)\.[a-z]+$/.test('report.csv'); // true
7.2 Lookbehind
Lookbehind is het spiegelbeeld. Hij asserteert wat er voor de huidige positie staat.
// Haal een prijs op na een valutasymbool — houd het getal, drop de $
'price: $42.50'.match(/(?<=\$)\d+(\.\d+)?/); // ['42.50', '.50']
// Negatieve lookbehind — match Bond maar niet James Bond
'Mr. Bond'.match(/(?<!James )Bond/); // ['Bond']
'James Bond'.match(/(?<!James )Bond/); // null
7.3 JavaScript vs. Python lookbehind
Dit is een van de weinige plekken waar de twee engines genoeg uiteenlopen om een patroon te breken wanneer je het port.
| Engine | Lookbehind-breedte |
|---|---|
| JavaScript (V8, SpiderMonkey, JSC 16.4+) | Variabele breedte sinds ES2018. (?<=\d+) is geldig. |
Python stdlib re | Alleen vaste breedte. (?<=\d+) werpt error: look-behind requires fixed-width pattern. |
Python regex PyPI-pakket | Variabele breedte ondersteund. import regex; regex.search(r'(?<=\d+)abc', '12abc'). |
Workaround in Python: herschrijf de lookbehind met een bekend aantal herhalingen ((?<=\d{3})), of capture de prefix en knip hem na het matchen weg.
8. Flags en modifiers
8.1 i: case-insensitive
/error/i.test('FATAL ERROR'); // true
re.search(r'error', 'FATAL ERROR', re.IGNORECASE) # <Match span=(6, 11)>
8.2 m en s
m maakt van ^ en $ per-regel-ankers. s (dotall) laat . ook newlines matchen. Ze zijn onafhankelijk; combineer ze wanneer je beide wilt.
/<script>(.*?)<\/script>/s.exec('<script>\nalert(1)\n</script>')[1];
// '\nalert(1)\n' — zonder s zou de . de newlines weigeren
8.3 g: globaal
In JavaScript verandert g de API, niet de match zelf. Zonder g geeft String.match capture-groepen terug; met g geeft het elke match-string terug. Gebruik matchAll om capture-groepen over alle matches heen te behouden.
const text = 'a=1 b=2 c=3';
text.match(/(\w)=(\d)/); // eerste match met groepen
text.match(/(\w)=(\d)/g); // ['a=1', 'b=2', 'c=3'] — geen groepen
[...text.matchAll(/(\w)=(\d)/g)]; // elke match, met groepen
Python gebruikt geen g; re.findall, re.finditer en re.sub zijn de globale varianten.
8.4 u: Unicode en \p{...}
// Match elk Han-teken (Chinees, Japans kanji)
/\p{Script=Han}+/gu.test('Hello 世界'); // true
// Match emoji (extended pictographic)
/\p{Extended_Pictographic}/u.test('👋'); // true
In Python staat Unicode standaard aan; re.findall(r'[一-鿿]+', text) is het equivalent voor het Han-bereik. Voor volledige Unicode property-escapes gebruik je het regex-pakket van PyPI: regex.findall(r'\p{Script=Han}+', text).
9. Veelgebruikte patronen voor dagelijks werk
9.1 E-mailvalidatie
Bepaal eerst welke versie je nodig hebt.
// Het 95%-patroon — wat de meeste formuliervalidators gebruiken
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
email.test('a@b.co'); // true
// Het "ik wil echt RFC 5322-achtig zijn"-patroon
const rfc = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
Volledige RFC 5322-emailvalidatie in pure regex is zo’n 6000 tekens lang en zit er nog steeds naast bij edge cases. Gebruik het 95%-patroon en stuur daarna een verificatiemail. Dat is de enige test die echt werkt.
9.2 URL-extractie
const urlPattern = /https?:\/\/[^\s<>"]+/g;
const found = 'See https://example.com/a?b=1 and http://x.io'.match(urlPattern);
// ['https://example.com/a?b=1', 'http://x.io']
Heb je een URL geëxtraheerd, dan wil je meestal naar de querystring kijken. Plak hem in onze URL Decoder & Encoder en je leest percent-encoded parameters in één oogopslag. Wil je de volledige uitleg over wanneer je encodeert en wanneer decodeert, lees dan de URL-encoderen en -decoderen: developer-gids voor percent encoding.
9.3 Telefoonnummers
// E.164 — internationaal, optionele + en landcode van 1-3 cijfers
const e164 = /^\+?[1-9]\d{1,14}$/;
e164.test('+14155551234'); // true
// Noord-Amerikaans nummerplan met scheidingstekens
const nanp = /^(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
nanp.test('(415) 555-1234'); // true
Voor alles meer dan “klopt de vorm ongeveer”, gebruik je libphonenumber. Een regex kan niet valideren of een netnummer bestaat.
9.4 IPv4 en IPv6
// IPv4 — strikt 0-255 per octet
const ipv4 = /^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$/;
ipv4.test('192.168.1.1'); // true
ipv4.test('999.0.0.1'); // false
// IPv6 — de vereenvoudigde vorm. Het volledige RFC 4291-patroon is ~600 tekens.
const ipv6simple = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
ipv6simple.test('2001:0db8:85a3:0000:0000:8a2e:0370:7334'); // true
Voor echt IPv6 met ::-afkorting, ingebedde IPv4 en zone-identifiers gebruik je isIP() uit node:net of ipaddress.ip_address() van Python. Het in pure regex proberen is een leuke oefening, en daarna een onderhoudslast.
9.5 ISO 8601-datums en -timestamps
// Alleen datum — YYYY-MM-DD
const isoDate = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
isoDate.test('2026-05-13'); // true
// Datum + tijd + optionele fractionele seconden + Z of offset
const iso = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
iso.test('2026-05-13T09:30:00.123Z'); // true
ISO 8601 lijkt simpel en zit vol valkuilen: schrikkelseconden, weekdatums (2026-W19), ordinale datums (2026-133). Voor epoch-seconden versus milliseconden en tijdzonewissels, zie de Unix timestamp omrekenen: precisie, tijdzone & DST-gids.
10. Find/replace-workflows met regex
10.1 JavaScript met String.replace en $1
// Herformatteer Amerikaanse datums: MM/DD/YYYY -> YYYY-MM-DD
'05/13/2026'.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$1-$2');
// '2026-05-13'
// Gebruik een callback wanneer de vervanging voorwaardelijk is
'price 42 dollars'.replace(/(\d+) dollars/, (_, n) => `$${n}`);
// 'price $42'
$1, $2, … verwijzen naar genummerde groepen. $<name> verwijst naar benoemde groepen. $& is de volledige match; $$ is een letterlijke $.
10.2 Python met re.sub, \1 en callbacks
import re
# Dezelfde datum-herformattering als hierboven
re.sub(r'(\d{2})/(\d{2})/(\d{4})', r'\3-\1-\2', '05/13/2026')
# '2026-05-13'
# Callback — maak elk e-mailadres in een string hoofdletters
def upper_email(m):
return m.group(0).upper()
re.sub(r'[\w.-]+@[\w.-]+', upper_email, 'mail me at hi@go-tools.org')
# 'mail me at HI@GO-TOOLS.ORG'
In vervangingen gebruikt Python \1 of \g<name>. Het raw string-prefix r'...' is belangrijk; zonder dat wordt \1 een letterlijk teken.
10.3 CLI: sed, grep, ripgrep, jq
Voor batch-refactors op de commandoregel verhuist regex van het script naar de shell:
# ripgrep — vind elke TODO met een naam erbij
rg -n '\bTODO\(([^)]+)\)' --replace 'TODO(\1)'
# grep -E met ankers — mislukte login-regels uit auth.log
grep -E '^[A-Z][a-z]{2} +[0-9]+ .*Failed password' /var/log/auth.log
# sed — strip trailing witruimte, in-place, over een boom
find . -name '*.md' -print0 | xargs -0 sed -i -E 's/[[:space:]]+$//'
ripgrep gebruikt de regex-crate van Rust (RE2-stijl, lineaire tijd, geen lookbehind). grep -E en sed -E gebruiken POSIX extended regex, dat geen \d heeft; gebruik in plaats daarvan [0-9] en [[:digit:]]. Is de data JSON, ruil regex dan in voor jq. Het jq spiekbriefje is de parallelle referentiekaart.
11. Veelvoorkomende valkuilen
11.1 Vergeten om . te escapen
Een bug die we ooit live hebben gezet: een log-redactor moest IP-adressen maskeren.
// Fout — matcht ook '192a168b1c1'
/(\d+).(\d+).(\d+).(\d+)/.test('192a168b1c1'); // true
// Goed
/(\d+)\.(\d+)\.(\d+)\.(\d+)/.test('192a168b1c1'); // false
Binnen een karakterklasse is . al letterlijk, dus zowel [.] als \. werken. Overal anders moet je escapen.
11.2 Greedy .* slokt te veel op
'<a href="x"><b>bold</b></a>'.match(/<(.*)>/)[1];
// 'a href="x"><b>bold</b></a' — alles!
Greedy .* scant tot het einde van de string en stapt dan terug tot > matcht. Dat is de laatste > in de input. Maak hem lazy (.*?) of, sneller en duidelijker, gebruik een genegeerde klasse ([^>]*).
11.3 Multiline-ankers
Een veelvoorkomende verwarring: ^ en $ matchen standaard geen newline-tekens. Ze matchen posities aan het begin en einde van de hele input. Pas met de m-flag worden het per-regel-ankers. En pas met de s-flag laat . newlines toe. Ze staan los van elkaar, en voor log-parsing wil je meestal allebei.
11.4 ReDoS en hoe je hem onschadelijk maakt
ReDoS, oftewel regex denial of service, is de productie-grade variant van catastrofale backtracking. De manieren om hem aan te pakken:
- Statische analyse. Tools als
safe-regex,rechecken ESLintsno-misleading-character-classvangen de gevaarlijke patronen voordat ze live gaan. - Atomic groups (Python
regex, PCRE, Ruby, Java):(?>...)voorkomt dat de engine de groep bij backtrack opnieuw binnen gaat. - Possessive quantifiers (
*+,++,?+in PCRE/Java): hetzelfde idee, kortere syntax. - Wissel naar een niet-backtrackende engine. Go’s
regexp, RE2, deregex-crate van Rust en dere2-Python-binding draaien allemaal in lineaire tijd. ripgrep is de populairste RE2-deployment in het wild. - Valideer eerst de input-lengte. Een 10 KB regex-bom is een bug; een 10 byte-limiet op de input is één regel code.
Voor een breder overzicht van de dagelijkse tools die naast regex horen, zoals formatters, decoders en converters, zie onze Essentiële developer tools (2026): encoderen, hashing, omrekenen.
Voordat je een complex patroon de wereld in stuurt, test je het interactief. regex101.com wisselt tussen PCRE-, JavaScript-, Python- en Go-smaken, legt elk token uit en laat het backtracken zien, zodat je catastrofale patronen herkent.
12. FAQ
Wat is het verschil tussen regex * en +?
* matcht nul of meer keer (mag dus ook een lege string matchen); + matcht één of meer keer (heeft minimaal één nodig). a* matcht '', 'a', 'aaaa'. a+ matcht 'a' en 'aaaa', maar niet ''.
Hoe match ik over meerdere regels met regex?
Zet de multiline-flag aan: /.../m in JavaScript, re.MULTILINE in Python. Daardoor verankeren ^ en $ zich aan elke regel. Wil je dat . ook newlines mag passeren, voeg dan de dotall-flag toe (s in JavaScript, re.DOTALL in Python).
Is regex hetzelfde in JavaScript en Python?
De kernsyntax (quantifiers, ankers, karakterklassen, basisgroepen) is voor 90% gelijk. De twee echte verschillen: JavaScript (ES2018+) ondersteunt variabele lookbehind en schrijft benoemde groepen als (?<name>...); Python stdlib re vereist lookbehind met vaste breedte en gebruikt (?P<name>...). Voor variabele lookbehind in Python installeer je het regex-pakket van PyPI.
Waarom heeft mijn regex catastrofale backtracking?
Je hebt geneste quantifiers met overlappende matches, zoals (a+)+ of (a|a)*. Op input die bijna matcht maar tegen het einde faalt, probeert de engine elke splitsing van de binnenste quantifier; dat zijn exponentieel veel paden. Los het op met een atomic group (?>a+)+, een possessive quantifier a++, of door te wisselen naar een niet-backtrackende engine zoals RE2 of Go’s regexp.
Kan ik lookbehind gebruiken in JavaScript?
Ja. Positieve (?<=...) en negatieve (?<!...) lookbehind zitten sinds ES2018 in V8 (Chrome, Node.js), SpiderMonkey (Firefox) en JavaScriptCore (Safari 16.4+). Variabele lookbehind wordt ondersteund. Voor oudere Safari transpileer je met Babel of doe je feature-detectie met een try/catch rond new RegExp.
Hoe match ik een letterlijke punt . in regex?
Escape hem met een backslash: \. matcht een letterlijke punt. Binnen een karakterklasse is de punt al letterlijk; zowel [.] als [\.] werken. Buiten een klasse is een niet-geëscapete . een metakarakter dat “elk teken behalve newline” betekent (of elk teken überhaupt met de dotall-flag).
Wat betekent \s in regex?
\s matcht elk witruimteteken — spatie, tab, newline, carriage return. In Unicode-modus matcht hij ook NBSP. \S is het omgekeerde.
Is regex hoofdlettergevoelig?
Standaard wel. Gebruik de i-flag in JavaScript (/cat/i) of re.IGNORECASE / (?i) in Python.