RegexEditor.dev Logo

Regex Editor & Tester

New FeaturePortabilityMulti-EngineFree

Cross-Engine Regex Compatibility CheckerOne regex, seven engines — will it survive the port?

Regex testers let you pick a flavor. None of them tell you what happens when the pattern you wrote for one language meets another. This feature runs your regex, flags and test string through seven engine paths simultaneously — real PCRE2, Go and Rust engines compiled to WebAssembly, native JS RegExp, and a .NET interpreter — groups the engines by whether they produce identical match sets, and flags every rejection, divergence and untestable construct per row. Free, in your browser, nothing uploaded.

7
Engine paths
3
Verdict states
1 click
From any pattern
Free
Forever

The portability problem

"Regular expressions" is not one language. It's a family of dialects that look almost identical and disagree in exactly the places you don't look until production breaks: \w is Unicode-aware by default in Python 3, PCRE2 and .NET, but ASCII-only in JavaScript. Lookbehind must be fixed-width in PCRE2; .NET accepts variable width; RE2-based engines reject lookbehind entirely. Possessive quantifiers, atomic groups, \K, named-group syntax (?<name>…) vs(?P<name>…) — every one of these is a line in some engine's grammar and an error (or worse, a silent behavior change) in another's.

The standard workflow makes this invisible. You test the pattern in one tester with one flavor selected, it works, you paste it into another language, and the failure shows up far away from the regex — a log line that never matches, a validation that rejects valid input, an import script that silently skips rows. By the time anyone connects the symptom back to the pattern, the regex has been through three people and a rewrite.

A flavor selector doesn't solve this — you still have to try every flavor by hand and compare results from memory. What you need is every engine answering at once, side by side, on the same input. That's what the Compat button does.

A 60-second tour

Type your pattern and a representative test string, then hit the Compat button in the toolbar — or share the deep link/compat directly:

The Compat button in the regex editor toolbar, between Debug and Format
The Compat button lives in the toolbar — one click from any pattern you're editing

The report opens and every engine starts working immediately; rows stream in as each one resolves. For a well-behaved pattern the outcome is short and sweet:

Compatibility report showing a fully compatible verdict: identical match results in all 7 engines
The happy path: this email pattern compiles and matches identically in all seven engine paths

Each row carries a badge naming its execution path — native, WASM engine, interpreter or emulated — so you always know what kind of evidence you're looking at. Click a row to expand the engine's own error message or a preview of its matches.

Same regex, different matches

Here is the case that makes the feature worth having. The pattern is as innocent as regexes get: \w+. The input is héllo wörld. Both compile everywhere. Both "work". And they split the engines into two camps with different outputs:

Compatibility report for backslash-w plus on héllo wörld: two clusters, JavaScript and Java find 4 matches while PCRE2, Python, .NET, Go and Rust find 2
Two clusters, one pattern: JS and Java match 4 words (ASCII \\w), the other five engines match 2 (Unicode \\w)

JavaScript's \w is [A-Za-z0-9_] unless the u flag with property escapes comes into play, so it finds h, llo,w, rld — four matches. PCRE2, Python, .NET, Go and Rust treat \w as Unicode-aware (Go and Rust by design, the others by default), matching héllo and wörld whole — two matches. Java's default \w is ASCII-only too, which is why it clusters with JavaScript.

No error is thrown anywhere. Port this pattern between any two of these engines and the behavior changes silently. The report makes the split visible in one glance: the verdict banner, the two colored cluster dots, and the differs marker on the minority rows.

The three ways a port fails

A pattern that uses \K — PCRE's "keep" escape, which resets where the reported match starts — fails differently in different engines. The report shows all three failure shapes in one view:

Compatibility report for a pattern using \K: PCRE2 matches, .NET is rejected with an unsupported escape error, Python is valid but untestable, the rest return different results
One construct, three outcomes: works (PCRE2), rejected (.NET), untestable (Python) — plus engines that silently match nothing
  • Works as intended. PCRE2 is the only engine doing what the author meant — one match, starting after \K. Its row is marked differs because it's the minority result.
  • Rejected outright. .NET refuses the pattern — expand the row and you get the engine's own error, not a paraphrase. You find this out here, instead of in a CI log three languages away from where the regex was written.
  • Silently does nothing. The remaining engines accept the pattern and match nothing — the strict \K is consumed as a literal K, and there is no K after the @. No error, no match: the worst failure mode, because nothing announces it.

One row reads valid · untestable here: the dialect parser accepts the syntax, but this site has no faithful execution path for it, so the row refuses to guess. That's a deliberate honesty rule — an untestable engine is labeled untestable, never quietly approximated.

How agreement is decided

Each engine's full match set is reduced to a signature: every match's position, matched text and capture groups. Engines with equal signatures are clustered under one colored dot; the cluster with the most engines is treated as the majority, and any ok-row outside it gets the differs marker. Signatures include positions and groups — not just match counts — because two engines can agree on how many matches while disagreeing on where they are, and that distinction matters when you port.

The verdict banner summarizes the state in one line, in one of three shapes:

  • Fully compatible — identical match results in all 7 engines — the signature test passed everywhere.
  • Compiles everywhere, but match results differ… — accepted by all, with two or more distinct outcomes.
  • 5/7 engines accept this pattern · … — a mixed report: acceptances, divergences, untestables and rejections, counted.

And one consistency guarantee by construction: every row runs through the same execution path the editor itself uses when you select that flavor manually. There is no separate "compatibility mode" — the report can never disagree with what you see when you switch flavors by hand.

The seven engine paths

Seven rows cover the eight flavors the tester supports (PCRE v1 rides along with PCRE2 — they share the dialect and engine here). The badge on each row says which of the four path types it is:

RowBadgeWhat actually runs
PCRE2WASM enginePCRE2 10.x compiled to WebAssembly in a worker — also covers PCRE v1
GoWASM engineThe Go regexp (RE2-lineage) engine compiled to WASM
RustWASM engineThe Rust regex crate compiled to WASM
JavaScriptnativeYour browser’s own RegExp engine (V8 and friends)
.NETinterpreterA TypeScript interpreter of System.Text.RegularExpressions semantics — balancing groups, conditionals, variable-length lookbehind
PythonemulatedValidity from the dialect parser; matches from a normalized equivalent executed on the JS engine
JavaemulatedSame split: parser verdict + normalized execution

The emulated rows are labeled emulated because pretending they're real engines would be the one unforgivable sin in a compatibility report: they answer "is this valid in the dialect, and what does the normalized equivalent match?" — which is what the editor shows for those flavors — not "what does CPython's or the JVM's engine do?" Every other row runs the production engine binary.

Honest limitations. A passing report is a strong signal, not a certification. Engine behavior also depends on flags, Unicode tables and runtime configuration (a production engine may reject a construct this build tolerates, or vice versa); the Python and Java rows are emulated, and everything runs on the engine versions compiled into this site. Treat the report as the fastest way to find portability bugs — not a substitute for your target engine's own test suite.

Exporting the report

One click copies the whole report as Markdown — verdict, per-engine outcomes with their execution paths, and the distinct-result groups when engines disagree. Paste it into a pull request, a migration ticket or an architecture-decision record, and the reviewer sees the portability evidence instead of taking your word for it:

## Regex Compatibility Report

Pattern `\\w+` · flags `gi` · 11-char test string · 2026-10-12, 09:41

**Compiles everywhere, but match results differ across engines (2 distinct outcomes) — see the groups below.**

| Engine | Execution path | Result |
|---|---|---|
| ✅ JavaScript | V8 RegExp (browser native) | 4 matches |
| ✅ PCRE2 | PCRE2 10.x WASM · also covers PCRE v1 | 2 matches |
| ✅ Python | dialect parser + normalized execution | 2 matches |
| ✅ Java | dialect parser + normalized execution | 4 matches |
| ✅ .NET | .NET semantics interpreter (TS) | 2 matches |
| ✅ Go | Go regexp (RE2) WASM | 2 matches |
| ✅ Rust | Rust regex crate WASM | 2 matches |

Distinct outcome groups:
- JavaScript, Java → 4 matches
- PCRE2, Python, .NET, Go, Rust → 2 matches

Because the report includes each row's execution path, the evidence stays auditable months later: readers can tell real-engine results from emulated ones without reverse-engineering the tool.

How it compares

Multi-flavor testers exist — you pick a flavor, the tester runs it. Running all flavors on one pattern and diffing the outputs is the part that has always been manual. This feature was built to delete that manual step:

CapabilityTypical regex testersThis compatibility checker
Engines per runOne — whichever flavor you selectedSeven paths simultaneously, results streaming in per row
Result comparisonYou switch flavors and compare from memoryMatch-set signatures cluster engines into agreeing groups automatically; minority rows marked differs
Real enginesVaries; often one engine approximating the restPCRE2, Go and Rust as real WASM-compiled engines, .NET semantics interpreter, native JS RegExp
Honesty labelsAll flavors presented as equalsEvery row badges its path: native / WASM engine / interpreter / emulated — untestable rows say so
Evidence exportScreenshot or nothingCopyable Markdown report with verdict, outcomes and execution paths
PriceMulti-engine anything tends to sit in a Pro tierFree, no account, runs entirely in your browser

Also in the box: deep link at /compat for sharing the report entry point, per-row engine error messages on expand, and a "How to read this report" primer built into the panel.

FAQ

Does the compatibility check send my patterns anywhere?›

No. All seven paths run locally in your browser — PCRE2, Go and Rust as WebAssembly, JavaScript natively, .NET through a TypeScript interpreter, Python and Java via the in-page dialect parser and normalized execution. Nothing is uploaded.

Why does the same regex match differently in different engines?›

Because the dialects genuinely differ: \w is Unicode-aware by default in Python 3, PCRE2 and .NET but ASCII-only in JavaScript and Java; \K exists only in the PCRE family; lookbehind width rules vary; RE2-lineage engines reject backtracking constructs outright. Same source text, different grammars.

What does "valid · untestable here" mean?›

The dialect parser accepts the syntax, but this site has no faithful execution path for it — for example a construct the normalizer cannot translate without changing its meaning. The row refuses to guess rather than showing an approximation as if it were the engine’s answer.

Do the Python and Java rows run the real engines?›

No — and they are labeled "emulated" for that reason. Their validity comes from the dialect parser and their matches from a normalized equivalent, exactly what the editor runs for those flavors. Treat them as a strong syntax check, not a CPython/JVM execution.

How is "identical results" defined?›

Two engines agree only if their full match sets match exactly: same positions, same matched text, same capture groups. Match counts alone are not enough — four matches at four different positions is a divergence, and the report treats it as one.

Does "fully compatible" guarantee identical production behavior?›

No. Flags, Unicode tables and engine versions all influence behavior, and a production engine may reject a construct this build tolerates. The report is the fastest way to surface portability bugs before they ship — final authority is always your target engine’s own tests.

Try it now

Your regex works here. Will it work there?

Open the tester, paste your pattern, press Compat. Ten seconds later you'll know which engines accept it, which ones agree, and exactly where the port breaks.

Open the Compatibility Checker