What survives
Published
Most compatibility questions about obfuscation are asked the wrong way round. For regular expressions the answer to “does it break?” is no, and it is no in a way that should make you look at your patterns again: they survive the transform completely unchanged, which means everything you encoded into them ships in the clear.
The measurement
A regular expression literal is a single token to the parser. It is read, carried through every transform, and written back out exactly as it arrived. Running a file of modern patterns through the protector and diffing the output against the input, the literals are identical character for character:
/(?<year>\d{4})-(?<month>\d{2})/u, /(?<=USD )\d+/g, /\p{Script=Han}+/gu, /token/y and a /v-flag character class all came back byte for byte. Named capture groups keep their names. Lookbehind survives. Unicode property escapes survive, flags and all.
That is the correct behaviour, and it is not an accident of laziness. A pattern is a self-contained mini-language with its own grammar; rewriting one safely would mean reimplementing that grammar, and the failure mode of getting it slightly wrong is a silent change in what your application matches. Leaving the literal alone is the conservative choice and it is the right one.
So read your patterns as if they were comments
The practical consequence is that every regular expression in your source is a readable comment that survives protection. Patterns are unusually informative because people encode business rules into them and rarely think of them as documentation.
An internal SKU format tells a reader how your catalogue is structured. A validation pattern for a partner reference number tells them which partners you have and what their identifiers look like. A pattern that recognises your own API paths maps your backend. A password policy regex publishes your password policy. A pattern matching competitor domains tells someone exactly which competitors you special-case.
None of this is a flaw in the transform. It is a reminder that obfuscation raises the cost of reading logic, and a regular expression is not logic in the sense that renaming and control-flow transforms operate on. It is data with a grammar, and it goes out as written.
The one case where a pattern does change
There is an asymmetry worth knowing, and it is the same asymmetry that shows up elsewhere in the engine. A pattern written as a literal is untouched. A pattern built from a string is a string like any other, so it goes into the string table when you enable MoveStrings with EncodeStrings.
Measured on the same file: new RegExp("(?<id>[a-z]+)", "u") came out with both arguments replaced by indexed lookups into an encoded array, and so did the replacement string "$<num>!" handed to .replace(). The behaviour is unchanged, because the value is reconstructed at runtime. What changes is that the text is no longer sitting in the file for someone running a grep over your bundle.
This is not a recommendation to rewrite your literals as strings. Doing that costs you compile-time validation of the pattern, costs a construction on every evaluation if you are careless about where you put it, and buys you only resistance to a text search. Someone who runs your code and inspects the constructed RegExp object still sees the pattern. It is worth knowing because it explains why two patterns in the same file can look different in the output.
What to actually do about it
Treat it as an inventory problem, not a transform problem. Grep your own bundle for /-delimited literals and read what comes back with fresh eyes, the way someone who has never seen your codebase would.
Where a pattern encodes something you would not put in a public document, the fix is the fix this site keeps arriving at: move the decision to a server you control. A licence key format check, an entitlement string match, a fraud heuristic and an internal routing rule are all decisions, and a decision that matters can be made somewhere the user cannot read or edit it. Validating format in the browser for a fast error message is fine; treating that validation as the enforcement point is not.
Where a pattern is genuinely harmless, which is most of them, leave it alone and enjoy the fact that this is one part of your build with no compatibility risk at all.
Frequently asked questions
Does obfuscation change how my regular expressions match?
No. A regular expression literal is carried through unchanged, so matching behaviour is identical before and after protection. Measured across named capture groups, lookbehind, Unicode property escapes, the sticky flag and the v flag, the literals came out byte for byte identical in both the default and the modern output targets.
Are named capture groups safe to use in protected code?
Yes. The group names live inside the pattern literal and are never renamed. Reading a group off the match result uses ordinary property access, so if you enable member renaming you should treat those reads the same way you treat any other property access and check the option's scope.
Can obfuscation hide the regular expressions in my bundle?
Not if they are written as literals, which is how nearly everyone writes them. Moving a pattern into a string does put it in the encoded string table, which stops a plain text search over the file, but anyone running the code can still inspect the constructed object. Do not treat either form as a place to keep something confidential.
Why do some patterns in my output look encoded and others do not?
Because the encoded ones were written as strings passed to new RegExp rather than as literals. Strings go into the string table when MoveStrings and EncodeStrings are enabled; literals do not. Both behave identically at runtime.
Does the sticky or global flag interact badly with obfuscation?
No. Flags are part of the literal and survive with it. The usual hazards of a stateful global or sticky pattern, principally a shared lastIndex across calls, are exactly as they were in your source and are not made better or worse by protection.
Should I stop putting business rules in regular expressions?
Not as a rule, but do stop treating a pattern in the browser as an enforcement point. Client-side format checks are good for user feedback. Anything that decides access, pricing or entitlement should be checked again on a server, because the pattern in the bundle is readable and editable by the person running it.
Related reading