Regex inline flags and scoped modifiers across engines
Most developers set regex flags outside the pattern, like the i after a JavaScript literal's closing slash. But many engines let you set those same flags inside the pattern with inline flag syntax, which is more portable and, crucially, can apply to just part of the expression.
The two forms
There are two related constructs, and the difference matters.
An inline flag setting like (?i) turns a flag on from that point to the end of the pattern (or the end of the enclosing group):
(?i)hello
This matches hello, HELLO, and Hello because (?i) switches on case insensitivity for everything after it. It behaves like the external i flag, just written inside the pattern.
A scoped modifier group like (?i:...) applies the flag only to the pattern inside its parentheses:
(?i:hello) World
Here hello is matched case insensitively but World is not, so HELLO World matches and hello WORLD does not. The scope ends at the closing parenthesis. This is the form you want when only part of the pattern should be case insensitive, which external flags cannot express at all.
The common flags
| Flag | Meaning |
|---|---|
i | Case insensitive |
m | Multiline: ^ and $ match at line breaks |
s | Dotall: . matches newlines too |
x | Extended: ignore whitespace and allow comments |
You can combine them, as in (?im), and some engines let you turn flags off with a minus, as in (?-i) to disable case insensitivity, or (?i-s) to turn one on and another off in the same group.
Engine support, with the JavaScript catch
This is where portability bites. The inline flag syntax is well supported in PCRE, Python's re, Java, .NET, Ruby, and Go's RE2. It is the normal way to write portable patterns in those ecosystems.
JavaScript is the notable exception. For years, JavaScript regex did not support inline flags at all; a pattern like (?i)foo would throw a syntax error, and all flags had to go on the literal or the RegExp constructor. Modern JavaScript added scoped modifier groups, so (?i:...) and (?i-m:...) work in current engines, but the bare (?i) form that sets a flag for the rest of the pattern is still not supported. So a pattern copied from a Python tutorial that opens with (?i) will fail in a browser, and this is one of the most common cross language regex surprises.
Python: (?i)cat works
JavaScript: (?i)cat SyntaxError
JavaScript: (?i:cat) works in modern engines
The x flag is worth knowing
The extended or x flag is underused and genuinely helpful for complex patterns, because it lets you lay a pattern out over several lines with whitespace and # comments, all ignored by the matcher:
(?x)
\d{4} # year
-
\d{2} # month
-
\d{2} # day
The one gotcha: because whitespace is now ignored, a literal space must be escaped as \ or put in a character class [ ], or it vanishes.
Practical advice
Prefer scoped modifier groups when only part of a pattern needs a flag; they are the one thing external flags cannot do, and they are now portable to modern JavaScript. For whole pattern flags, know that (?i) style prefixes are portable across most engines but not JavaScript, so when a pattern must run in the browser, set flags externally instead. And always test the pattern in the engine you will actually run it in, because the syntax that parses in one can throw in another.
Try inline and scoped flags against live input and see exactly what matches with the Regex Tester.