Technical note · RegexPilot
What supporting 21 regex engines actually involves
“21 engines” sounds like a feature list. In practice, it is a long exercise in accepting that the same pattern is not the same program.
RegexPilot is a visual regex builder for macOS. One of its less visible features is that it can test a pattern against 21 different regex engines. The visible part is a selector. The hard part is everything behind it.
The selector is the easy part
A dropdown with 21 names is not engine support. Each engine has its own parser, its own accepted syntax and its own idea of what a particular construct means. A pattern that is valid JavaScript is not automatically valid Python, Java, Ruby or Perl. A pattern that compiles everywhere can still return different matches.
Supporting an engine means understanding its dialect well enough to explain it in the interface, test it against real examples and avoid pretending that every feature exists everywhere.
Syntax drifts quietly
Most of the common syntax is shared, which is exactly what makes the differences dangerous. Inline flags, named groups, lookbehind, Unicode property escapes, possessive quantifiers and conditional patterns are not distributed evenly across engines. Some features are recent additions; some are deliberately unsupported; some look similar but behave differently at the edges.
For a visual tool, the problem is doubled: the block canvas has to represent the pattern faithfully, while the underlying engine has to receive valid syntax. A friendly abstraction is only useful if it does not lie about what the target engine can do.
Features are uneven
- Some engines support lookbehind; others do not, or only with restrictions.
- Named capture groups use different syntax and different naming rules.
- Unicode handling varies from engine to engine and sometimes by mode.
- Replacement syntax is not interchangeable, even when matching is.
- Performance characteristics differ enormously on pathological patterns.
Those are not edge cases to hide. They are part of what the user needs to know before shipping a pattern into production.
Match semantics is the hard part
Two engines can accept the same expression and disagree about the result. Greedy versus lazy behaviour is usually consistent, but zero-width matches, capture-group numbering, duplicate names, newline handling and Unicode case folding can produce different match sets. Testing against one engine and assuming the rest will behave identically is how regex bugs reach production.
The real feature is not “supports 21 engines.” It is “tells you when those engines disagree.”
Testing becomes a product feature
With one engine, a test suite is mostly about the patterns you write. With 21, the test matrix becomes part of the product. Each supported engine needs representative patterns, negative cases and a way to verify that a feature is genuinely supported rather than merely accepted by the parser.
That is why RegexPilot includes live match testing, unit tests, replacements, a pattern library and a two-way VS Code bridge. The bridge matters because the most useful place to test a regex is often the editor where it will actually be used.
What this changed in RegexPilot
Supporting multiple engines forced a stricter separation between the visual model, the generated pattern and the engine-specific runtime. It also made the UI more honest: the canvas can show a construct, but the engine panel has to say whether the selected engine supports it and what happens when it does not.
The product is built with Rust and Tauri, shipped on the Mac App Store, and still evolving. The engine layer is one of the reasons it is a product rather than a demo: the interesting engineering is in the differences, not in the happy path.
RegexPilot is an independent macOS app for building, testing and understanding regular expressions.
See RegexPilot →