Start here¶
One line: This library answers regular-expression questions by running them — in Rust, Python and ABAP first, then Perl, JavaScript, Ruby, Java, Go, grep and sed — because the interesting part of a regular expression is almost always where the engines disagree.
The one rule¶
A page never claims something a program has not printed. Every output block on every lesson is pasted in by tools/run_examples.py from a real run, and CI fails if a page and its program drift apart. When you read ['25', '90'] on the lookaround page, that is what Python printed, not what the author remembered.
There is one exception, and it is marked: ABAP. Nothing here — and nothing on a GitHub runner — has an ABAP system, so .abap files are pasted as source and never carry an answer key. Where the engine underneath ABAP can be shown, it is shown honestly, as a dated transcript from PCRE2 on the machine that wrote the page.
Where to go¶
| If you want | Go to |
|---|---|
What one piece of syntax means, per engine — \b, (?>…), $1, \K |
Keywords, one page per construct, each with an eight-engine table |
| How to do a job — validate a field, split a line, port a pattern | Topics, one page per job |
The thing \1 actually means |
What a backreference is |
\1 written before its group — and the names people confuse it with |
Forward references |
Why $1 and \1 are not the same feature |
Backreferences in the replacement |
| Why Go and Rust refuse backreferences | What a backreference costs |
(?=…), (?<=…), and how wide a lookbehind may be |
Lookahead and lookbehind |
| A table of which engine has which construct | Who supports what |
| Books and the official documentation | Resources |
Where to go when something is already wrong¶
Most of this library exists because a pattern that looks right is not, and the failure is a match result rather than an error message. If one of these is your afternoon, start here instead of at the beginning:
| The symptom | The page |
|---|---|
| A request hangs; a pattern is fast on test data and not in production | Catastrophic backtracking |
| Somebody made a pattern faster and it stopped matching | Atomic groups and possessive quantifiers |
| A validator rejects somebody's name, or accepts a "number" the language cannot parse | What \w and \b match |
\p{L} does nothing, or works in one language and not the next |
Naming a Unicode property |
(?i) matched something you did not expect it to |
(?i) is a folding table |
^…$ let something through that it should not have |
$ is not the end of the string |
| The same flag letter means something else in the other language | Flags, and where you can turn one on |
| The pattern matches in both engines and hands back different text | Leftmost-first and leftmost-longest |
Someone told you .*? is the fast one |
Greedy and lazy |
| You are about to match something nested | Matching nested structures |
| One pattern has to handle an optional delimiter properly | Conditionals and (?(DEFINE)…) |
The four lineages¶
Nearly every engine you will meet is one of four, and knowing which one you are holding predicts more than any single fact:
- Perl / PCRE2 — the biggest feature set. Perl, PCRE2, PHP, and ABAP's
PCREaddition since release 7.55. - The middle ground — Java, Ruby, JavaScript, C#. Perl-like, each missing a different corner.
- Python
re— Perl-like, stricter about lookbehind width and forward references. - Automata — Go's
regexp, Rust'sregex, RE2. No backreferences, no lookaround, and a guarantee of linear time in exchange.
Running it yourself¶
python3 tools/run_examples.py # run every example, refill every page
python3 tools/check_all.py # everything CI runs, in CI's order
uv run --group docs mkdocs serve # preview the site locally
The Rust answers need a crate, because Rust has no regular expressions in its standard library; they run through the small Cargo workspace in rust-demo/ from a .sh example. Everything else uses the language's own standard library.