A regex pattern that works perfectly in Python may fail silently in JavaScript or match differently in Go. These differences stem from the underlying regex engines, each of which implements a slightly different subset of regex features with subtly different semantics. Understanding these differences prevents bugs when moving patterns between languages or environments.

The Major Engine Families

There are three main families of regex engines: PCRE-compatible engines (PHP, R, Nginx), Perl-derived engines (Perl, Java, .NET, Ruby), and ECMAScript engines (JavaScript, TypeScript). Go uses RE2, a fundamentally different engine that guarantees linear-time matching by omitting features like backreferences and lookaheads. Each family shares a common core syntax but diverges on advanced features.

Feature Differences That Matter

Lookaheads are supported everywhere, but lookbehinds vary. JavaScript only added lookbehinds in ES2018, and Go’s RE2 engine does not support them at all. Named capture groups use `(?P<name>...)` in Python but `(?<name>...)` in JavaScript and Java. Possessive quantifiers (`a++`) work in Java and PCRE but not in JavaScript or Python’s built-in `re` module.

Unicode Handling

Unicode support is one of the biggest areas of divergence. JavaScript requires the `u` flag for proper Unicode matching. Python 3 handles Unicode by default but Python 2 does not. Java requires `Pattern.UNICODE_CHARACTER_CLASS` for Unicode-aware character classes. Go’s RE2 handles Unicode well by default. If your patterns use `\w`, `\d`, or `.`, test thoroughly across engines because these metacharacters match different character sets depending on Unicode mode.

Performance Characteristics

PCRE and Perl-style engines use backtracking, which enables powerful features but risks catastrophic backtracking on pathological inputs. RE2 uses a Thompson NFA algorithm that guarantees O(n) matching time but cannot support backreferences. For user-facing applications where untrusted patterns or inputs might trigger worst-case behavior, RE2-style engines are safer. For developer tools where patterns are controlled, backtracking engines offer more features.

The .NET Exception

.NET’s regex engine is uniquely powerful. It supports variable-length lookbehinds (most engines require fixed-length), balancing groups for matching nested structures, and right-to-left matching mode. If you develop a pattern in .NET and then try to port it to JavaScript, you may find that several features simply do not exist.

Practical Advice

When writing regex patterns that may be used across languages, stick to the common subset: character classes, basic quantifiers, alternation, lookaheads, and numbered capture groups. Test in your target environment before deploying. RegExpress for iOS supports multiple regex flavors, making it easy to verify that your pattern behaves consistently across different engines.