Developer Tools

What are regex flags and when should I use them?

Learn about regular expression flags that modify pattern matching behavior, including case-insensitivity, multiline, and global flags.

By Inventive HQ Team

Understanding Regex Flags

A regex flag is a single-letter modifier attached to a regular expression that changes how the entire pattern is matched — without changing the pattern itself. The seven you will actually meet are g (global, match everywhere), i (ignore case), m (multiline anchors), s (dotall, let . match newlines), u (Unicode), y (sticky, JavaScript only), and x (extended/verbose, everywhere except JavaScript). In JavaScript you append them after the closing slash — /hello/gi — and in Python you pass them as arguments, re.compile("hello", re.I). The same pattern can behave completely differently depending on which flags are set.

That is the summary an AI overview will give you. What it won't tell you is where the languages quietly disagree — JavaScript has no verbose flag, Python has no global flag, and PHP will throw an error if you copy a JavaScript /g into it. The reference table and diagram below are the parts you can actually keep at your desk.

The regex flag cheat sheet

Every flag you are likely to use, what it changes, a minimal example, and whether it exists in JavaScript and Python. This is the table to bookmark.

FlagNameWhat it changesExampleJavaScriptPython
gGlobalFind/replace every match, not just the first/a/g on "aaa" → 3 matches/a/gno flag — findall / sub act on all
iIgnore-caseMatch regardless of upper/lower case/hello/i matches "HELLO"/x/ire.I / re.IGNORECASE
mMultiline^ and $ match at every line break, not just string ends/^b/m matches the b in "a\nb"/x/mre.M / re.MULTILINE
sDotall (single-line). also matches newline characters/a.b/s matches "a\nb"/x/sre.S / re.DOTALL
uUnicodeRead the pattern as Unicode code points; enables \u{…} and \p{…}/\p{L}/u matches any letter/x/uon by default in Python 3 (re.U)
yStickyMatch only at the regex's lastIndex — no scanning ahead/a/y/x/yno sticky flag
xExtended (verbose)Ignore whitespace and allow # comments inside the patterncommented multi-line patternnot supportedre.X / re.VERBOSE

Two rows carry the surprises most people trip on: JavaScript has no x flag, so you can't write a whitespace-and-comments pattern the way you can in Python or PHP; and Python has no g flag, because whether you get one match or all of them is decided by the function you call (re.search vs re.findall/re.sub), not by a modifier.

Anatomy of a flagged regular expression A JavaScript regex literal slash-pattern-slash followed by the flag letters g, i, m, s, u, y, x, with a highlight pulsing across each flag in turn. A flag is a modifier bolted onto the pattern The pattern says what to match; the flags say how /\d{3}-\d{4}/ the pattern g i m s u y the flags Same pattern, different behavior: add g to catch all matches, i to ignore case, s to let the dot cross line breaks — the pattern text never changes. JavaScript syntax shown; Python passes the same ideas as re.I, re.M, re.S …

A regex flag is a single letter code that modifies pattern behavior. Different programming languages use slightly different syntax for flags, but the core flags are remarkably consistent. For example, the case-insensitive flag is typically i across JavaScript, Python, Perl, and most other languages.

Loading interactive tool...

Use the tester above to watch flags change behavior in real time — toggle g, i, m, and s on a sample string and see which matches light up. The rest of this guide explains what each one is doing under the hood.

The Most Common Regex Flags

Case-Insensitive Flag (i)

Makes the pattern ignore uppercase/lowercase distinctions.

Without i flag:

/hello/.test("Hello World")  // false
/hello/.test("hello world")  // true

With i flag:

/hello/i.test("Hello World")  // true
/hello/i.test("hello world")  // true
/hello/i.test("HELLO world")  // true

Use Cases:

  • User input validation where case doesn't matter
  • Search functionality (users expect case-insensitive search)
  • Data matching when values are stored in different cases
  • Email addresses (technically case-insensitive)

Language Examples:

import re
pattern = re.compile(r'hello', re.IGNORECASE)  # or re.I
pattern.search("Hello World")  # Match!

# JavaScript
/hello/i.test("Hello")  // true

# PHP
preg_match('/hello/i', "Hello")  // true

Global Flag (g)

Finds all matches instead of stopping after the first match.

Without g flag:

"hello world hello".match(/hello/)  // ["hello"]

With g flag:

"hello world hello".match(/hello/g)  // ["hello", "hello"]
What the global flag changes The same string scanned twice. Without the g flag only the first "cat" is highlighted; with the g flag a marker sweeps across and highlights all three occurrences. Without g: stops at the first match. With g: finds them all. /cat/ the cat sat by a cat near a cat 1 match — the engine returns as soon as it succeeds /cat/g the cat sat by a cat near a cat 3 matches — g keeps scanning to the end of the string

Use Cases:

  • Find all occurrences of a pattern
  • Replace all matches (not just first)
  • Count total matches
  • Extract multiple values from text

Language Examples:

import re
text = "hello world hello"
re.findall(r'hello', text)  # ['hello', 'hello']

# JavaScript
"hello world hello".match(/hello/g)  // ["hello", "hello"]

# PHP
preg_match_all('/hello/', "hello world hello", $matches);
// $matches[0] contains all matches
Advertisement

Multiline Flag (m)

Makes ^ and $ match line boundaries, not just string boundaries.

Without m flag:

String: "line1\nline2\nline3"
Pattern: ^line
Matches: Only "line1" at start of string

With m flag:

String: "line1\nline2\nline3"
Pattern: ^line
Matches: "line1", "line2", "line3" (each line start)

Use Cases:

  • Processing multi-line text documents
  • Log file analysis
  • Text where each line is processed separately
  • Validation where ^ and $ should apply per-line

Language Examples:

import re
text = "line1\nline2\nline3"
re.findall(r'^line', text, re.MULTILINE)  # ['line1', 'line2', 'line3']

# JavaScript
"line1\nline2\nline3".match(/^line/gm)  // ["line1", "line2", "line3"]

Dotall/Single-Line Flag (s)

Makes . (dot) match newline characters in addition to regular characters.

Without s flag:

String: "hello\nworld"
Pattern: hello.world
Matches: No (dot doesn't match \n)

With s flag (varies by language):

String: "hello\nworld"
Pattern: hello.world
Matches: Yes

Use Cases:

  • Matching patterns across newlines
  • HTML/XML parsing (content spanning lines)
  • Comments or multi-line strings
  • Processing formatted text

Language Examples:

import re
text = "hello\nworld"
re.search(r'hello.world', text, re.DOTALL)  # Match!

# JavaScript (called 's' flag)
/hello.world/s.test("hello\nworld")  // true

Extended/Verbose Flag (x)

Allows whitespace and comments in the pattern for readability.

Without x flag:

^\d{3}-\d{3}-\d{4}$

With x flag:

^
\d{3}      # Area code
-          # Separator
\d{3}      # Exchange
-          # Separator
\d{4}      # Line number
$

Both match the same pattern, but the second is much more readable.

Use Cases:

  • Complex patterns that need explanation
  • Team collaboration (comments help others understand)
  • Maintenance (you'll remember why you wrote it)
  • Patterns that are frequently modified

Language Examples:

import re
pattern = re.compile(r'''
    ^(\d{3})      # Area code
    -(\d{3})      # Exchange
    -(\d{4})$     # Line number
''', re.VERBOSE)

# JavaScript doesn't have native verbose flag
// Must use comments in string:
const pattern = /^(\d{3})-(\d{3})-(\d{4})$/
// Comment after regex

Language-Specific Flags

Additional Python Flags

re.ASCII (a): Makes \w, \s, \d match ASCII only (not Unicode)

re.LOCALE (L): Makes \w, \s, \d locale-dependent

re.UNICODE (u): Makes \w, \s, \d match Unicode (default in Python 3)

Additional JavaScript Flags

u (Unicode): Treats the pattern as a sequence of Unicode code points and enables \u{…} escapes and \p{…} property classes.

v (unicodeSets): A newer, stricter upgrade of u (ES2024) that adds set operations and string properties inside character classes. Use v or u, not both.

y (Sticky): Matches only at the regex's lastIndex position — it will not scan forward to find a match. Useful for tokenizers.

d (hasIndices): Adds a .indices array to each match giving the start/end offset of every capture group (ES2022). It changes the result shape, not what matches.

Gotcha — the stateful lastIndex: a regex carrying g or y remembers where it left off between .test() / .exec() calls on the same regex object. Reuse one for repeated boolean checks and every other call can surprise you. Drop g when you only need true/false, or reset regex.lastIndex = 0.

Additional Perl-Compatible Flags

e: Evaluates replacement as code (dangerous, avoid)

o: Compiles pattern once

Combining Multiple Flags

Most languages allow combining multiple flags:

JavaScript:

/pattern/gim  // global, case-insensitive, multiline
/pattern/gi   // global, case-insensitive

Python:

re.compile(pattern, re.IGNORECASE | re.MULTILINE)
re.compile(pattern, re.I | re.M)

PHP:

preg_match('/pattern/ims', $text)  // Combined modifiers
// Note: PCRE has NO g modifier — /pattern/gim throws
// "Unknown modifier 'g'". Use preg_match_all() for "global".

Common Flag Combinations

Search and Replace (All Matches, Case-Insensitive)

Flags: /g/i or gi
Why: Need all matches (g) and ignore case (i)

JavaScript:

"Hello world hello".replace(/hello/gi, "hi")
// "hi world hi"

Multi-Line Processing (Case-Insensitive)

Flags: /m/i or mi
Why: Process each line separately (m) and ignore case (i)

Python:

re.findall(r'^hello', text, re.M | re.I)

Complex Pattern with Comments

Flags: /x/g or xg
Why: Verbose for readability (x), all matches (g)

Flag Syntax Across Languages

TaskJavaScriptPythonPHPPerl
Case-insensitive/ire.I/i/i
Global/g- (use findall)- (use preg_match_all)/g
Multiline/mre.M/m/m
Dotall/sre.S/s/s
Verbose-re.X/x/x
Sticky/y---
Combine/gimre.I|re.M/ims/gim

PHP/PCRE has no g modifier — writing /pattern/gim raises "Unknown modifier 'g'". Use preg_match_all() for global matching. The sticky (y) flag is JavaScript-only.

Practical Examples

Find All Email Addresses (Case-Insensitive)

import re
text = "Contact John@Example.com or JANE@COMPANY.ORG"
emails = re.findall(r'[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}', text, re.IGNORECASE)
# Result: ['John@Example.com', 'JANE@COMPANY.ORG']

Replace All Occurrences (Case-Insensitive)

let text = "The cat and the Cat are friends";
let result = text.replace(/cat/gi, "dog");
// Result: "The dog and the dog are friends"

Parse Log Lines (Multiline)

import re
log = """
ERROR: System failure
INFO: System started
WARNING: Memory low
ERROR: Disk full
"""
errors = re.findall(r'^ERROR:.*$', log, re.MULTILINE)
# Result: ['ERROR: System failure', 'ERROR: Disk full']

Validate Across Lines (Dotall)

let html = "<div>\n  content\n</div>";
let matched = /<div>.*?<\/div>/s.test(html);
// true (. matches the newlines)

Complex Pattern with Explanation (Verbose)

import re
pattern = re.compile(r'''
    (?P<year>\d{4})      # Year
    -                    # Separator
    (?P<month>\d{2})     # Month
    -                    # Separator
    (?P<day>\d{2})       # Day
''', re.VERBOSE)

date = "2024-01-15"
match = pattern.match(date)
# match.group('year') = '2024'

Performance Implications

Flags Impact on Performance:

  • i flag: Slight slowdown (case-conversion required)
  • g flag: Normal speed (finds all matches)
  • m flag: Normal speed (different matching strategy)
  • s flag: Minimal impact
  • x flag: Compiled pattern same speed (whitespace removed during compilation)

Generally, flags have negligible performance impact. Focus on pattern efficiency rather than flag choice.

Common Mistakes with Flags

Forgetting Global Flag for Replace

WRONG: "hello world hello".replace(/hello/, "hi")
// Result: "hi world hello" (only first replaced)

RIGHT: "hello world hello".replace(/hello/g, "hi")
// Result: "hi world hi" (all replaced)

Forgetting Case-Insensitive for Validation

WRONG: /^[a-z]+$/.test("Hello")  // false
RIGHT: /^[a-z]+$/i.test("Hello")  // true

Multiline Flag Confusion

WRONG: ^hello$ finds "hello" anywhere in line
RIGHT: ^hello$ with /m flag finds "hello" at line start

Not Combining Flags When Needed

WRONG: Pattern with only /g (might want case-insensitive too)
RIGHT: Pattern with /gi (global + case-insensitive)

Checking Active Flags

Most languages allow checking which flags are active:

JavaScript:

let pattern = /test/gi;
console.log(pattern.flags);  // "gi"
console.log(pattern.global);  // true
console.log(pattern.ignoreCase);  // true

Python:

pattern = re.compile(pattern_str, re.I | re.M)
print(pattern.flags)  // Shows combined flags

Conclusion

Regex flags are powerful modifiers that change pattern behavior without requiring pattern rewrites. The most commonly used flags are case-insensitive (i), global (g), and multiline (m). Understanding when to apply each flag dramatically improves your ability to write correct and efficient patterns. When in doubt about flag syntax, check your language's documentation, but the core concepts remain consistent across programming languages. Combine flags when needed, and always test your patterns with various input to ensure flags achieve the desired behavior.

Frequently Asked Questions

What is a regex flag?

A regex flag is a single-letter modifier attached to a regular expression that changes how the whole pattern is matched, without changing the pattern itself. In JavaScript you append flags after the closing slash (/hello/gi); in Python you pass them as arguments (re.compile('hello', re.I)). The same underlying pattern can behave completely differently depending on which flags are set — matching every occurrence instead of the first, ignoring letter case, or letting the dot match newlines.

What are the g, i, and m flags in regex?

They are the three most common flags. The g (global) flag finds every match in the string instead of stopping at the first one — it is what makes replace-all work. The i (ignore-case) flag matches regardless of upper or lower case, so /apple/i matches "APPLE". The m (multiline) flag makes the anchors ^ and $ match at the start and end of every line, not just the start and end of the whole string. Note that Python has no g flag — you use re.findall or re.sub, which act on all matches by default.

What does the s (dotall) flag do?

By default the dot (.) in a regex matches any character except a line break. The s flag — called "dotall" or "single-line" mode — removes that exception so the dot also matches newline characters. It is useful when you need a pattern to span multiple lines, such as capturing everything between an opening and closing HTML tag that sits on separate lines. It exists as /s in JavaScript and re.S / re.DOTALL in Python. Do not confuse it with multiline mode (m), which changes what the anchors do, not what the dot does.

Does JavaScript have a verbose or extended (x) flag?

No. JavaScript has never shipped an extended/verbose (x) flag, so you cannot add whitespace and inline # comments inside a JavaScript regex literal to make it readable. This is a genuine difference from Python (re.X / re.VERBOSE), PCRE/PHP (/x), and Perl (/x), all of which support it. In JavaScript you either keep the pattern compact and comment it in the surrounding code, or build it from smaller strings with the RegExp constructor.

How is the global flag different in JavaScript versus Python?

In JavaScript, g is an actual flag you attach to the regex, and it changes the behavior of methods like match, matchAll, and replaceAll, and it makes .test() and .exec() advance a stateful lastIndex between calls. Python has no global flag at all: whether you get one match or all of them is decided by which function you call — re.search finds the first, re.findall and re.finditer find all, and re.sub replaces all by default. Forgetting this is a common source of confusion when porting patterns between the two languages.

What does the sticky (y) flag do in JavaScript?

The y (sticky) flag forces the match to start exactly at the regex's lastIndex position instead of scanning forward through the string to find one. If there is no match at that precise position, it fails immediately rather than looking further ahead. It is mainly used when building tokenizers and parsers, where you want to consume the input strictly left to right. It is a JavaScript feature; Python has no sticky flag, though re.match plus an explicit position argument achieves something similar.

How do I combine multiple regex flags?

In JavaScript you write the letters together after the closing slash in any order — /pattern/gis means global, case-insensitive, and dotall all at once. In Python you combine flags with the bitwise OR operator: re.compile(pattern, re.I | re.M | re.S). In PCRE/PHP you concatenate the modifier letters like /pattern/ims. The order never matters; flags are a set, not a sequence.

Do regex flags slow down matching?

In practice, no meaningfully. The ignore-case (i) flag adds a small amount of work because the engine must compare characters in a case-folded way, and the unicode (u) flag changes how the pattern is parsed, but for normal inputs the difference is negligible. The x (verbose) flag has zero runtime cost because the whitespace and comments are stripped when the pattern is compiled. Real regex performance problems come from the pattern's structure — catastrophic backtracking — not from which flags you set.

Why is my global-flag regex only matching every other time?

This is a classic JavaScript trap. A regex with the g (or y) flag stores a lastIndex property and advances it each time you call .test() or .exec() on the same regex object. Call .test() twice on the same string and the second call resumes from where the first left off, so it can return false unexpectedly. The fix is to not reuse a global regex for repeated one-off tests — create a fresh regex, drop the g flag when you only need a boolean, or reset lastIndex to 0 between calls.

regexflagsmodifierspattern matching