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.
| Flag | Name | What it changes | Example | JavaScript | Python |
|---|---|---|---|---|---|
g | Global | Find/replace every match, not just the first | /a/g on "aaa" → 3 matches | /a/g | no flag — findall / sub act on all |
i | Ignore-case | Match regardless of upper/lower case | /hello/i matches "HELLO" | /x/i | re.I / re.IGNORECASE |
m | Multiline | ^ and $ match at every line break, not just string ends | /^b/m matches the b in "a\nb" | /x/m | re.M / re.MULTILINE |
s | Dotall (single-line) | . also matches newline characters | /a.b/s matches "a\nb" | /x/s | re.S / re.DOTALL |
u | Unicode | Read the pattern as Unicode code points; enables \u{…} and \p{…} | /\p{L}/u matches any letter | /x/u | on by default in Python 3 (re.U) |
y | Sticky | Match only at the regex's lastIndex — no scanning ahead | /a/y | /x/y | no sticky flag |
x | Extended (verbose) | Ignore whitespace and allow # comments inside the pattern | commented multi-line pattern | not supported | re.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.
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.
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"]
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
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
| Task | JavaScript | Python | PHP | Perl |
|---|---|---|---|---|
| Case-insensitive | /i | re.I | /i | /i |
| Global | /g | - (use findall) | - (use preg_match_all) | /g |
| Multiline | /m | re.M | /m | /m |
| Dotall | /s | re.S | /s | /s |
| Verbose | - | re.X | /x | /x |
| Sticky | /y | - | - | - |
| Combine | /gim | re.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.