The dot and flags
Understand the dot wildcard's exact behaviour and how flags i, g, m, s, and x modify pattern matching.
- Predict exactly what . matches and when it does not match newlines
- Apply the i flag for case-insensitive matching
- Use the g flag to find all matches rather than just the first
- Switch line vs string anchoring with the m flag
- Enable dotall mode with the s flag
The dot . and regex flags are two of the most frequently used — and most
frequently misunderstood — features in a regex pattern. This lesson pins down
exactly what they do.
The dot in depth
Outside a character class, . matches any single character except a newline
(\n):
/h.t/.test("hat"); // true — 'a' matches .
/h.t/.test("h\nt"); // false — newline does not match .
/h.t/.test("h t"); // true — space matches .
/h.t/.test("h"); // false — . requires exactly one characterThe dot is a wildcard, not a "skip anything" operator. It consumes exactly one
character — no more, no less. This matters when combining it with quantifiers:
/.+/ matches one or more of any character (except newline).
Overusing . is a common beginner mistake. When you want "any letter" or "any
digit," use a character class ([a-z], \d) rather than . — it makes the
pattern's intent explicit and avoids accidental matches. Reserve . for genuine
"I don't care what this character is" situations.
Inside a character class, . is a literal dot:
/[.]/.test("."); // true — literal dot
/[.]/.test("a"); // false — only matches a periodThis is a useful trick for matching a literal dot without escaping: [.] is more
readable to some people than \..
Flags
Flags appear after the closing / in a JavaScript regex literal, or as options
passed to the regex constructor. They modify how the entire pattern behaves.
i — case-insensitive
Without i, /hello/ does not match "Hello". With it:
/hello/i.test("Hello"); // true
/hello/i.test("HELLO"); // true
/^[a-z]+$/i.test("MixedCase"); // true — character ranges also become case-insensitiveThe i flag is the quickest way to handle user input where you do not want to
normalise case first.
g — global (find all matches)
Without g, .match() and .exec() return only the first match. With g, you
get every non-overlapping match:
"one two three".match(/\w+/); // ["one"]
"one two three".match(/\w+/g); // ["one", "two", "three"]String.prototype.replace also respects g:
"aabbcc".replace(/[a-c]/g, "x"); // "xxxxxx"
"aabbcc".replace(/[a-c]/, "x"); // "xabbcc" — only firstWhen using .exec() in a loop with the g flag (an older pattern), the regex
object maintains a lastIndex property that advances after each call. Modern
code usually prefers String.prototype.matchAll() which returns an iterator of
all match objects cleanly.
m — multiline
Makes ^ and $ match at the start and end of each line rather than just the
start and end of the entire string:
const log = "INFO: started\nERROR: failed\nINFO: done";
log.match(/^ERROR.*/); // null — ERROR is not at string start
log.match(/^ERROR.*/m); // ["ERROR: failed"]
log.match(/^INFO.*/gm); // ["INFO: started", "INFO: done"]The m flag is most useful when processing multi-line text where you want to work
line by line.
s — dotall (dot matches newline)
Makes . match newline characters too, so it truly matches any character:
/hello.world/.test("hello\nworld"); // false — newline blocked by .
/hello.world/s.test("hello\nworld"); // true — s flag enables dotallThe s flag is useful when matching content that spans multiple lines, like
extracting a block between two markers:
const html = "<div>\n content here\n</div>";
html.match(/<div>.*<\/div>/s); // matches the whole blocku — unicode
Enables full Unicode mode. In JavaScript, without u, certain Unicode escapes and
character class behaviour are limited:
/^\p{L}+$/u.test("café"); // true — \p{L} is Unicode letter category
/^\p{Emoji}$/u.test("😀"); // trueThe u flag is important for non-ASCII text — names, emoji, and international
content. Without it, some Unicode patterns are silently wrong.
x — extended / verbose (Python and some others, not in JavaScript)
Not available in JavaScript. In Python, the re.VERBOSE flag (re.X) lets you
add whitespace and comments inside a pattern to improve readability:
import re
pattern = re.compile(r"""
\d{4} # year
-
\d{2} # month
-
\d{2} # day
""", re.VERBOSE)This is invaluable for long, complex patterns that would otherwise be incomprehensible.
Flag combinations
Flags stack — just append them:
/\d+/gi // global + case-insensitive (i is irrelevant for digits, but valid)
/^error/gim // global + case-insensitive + multilineIn Python, combine flags with |:
re.search(pattern, text, re.IGNORECASE | re.MULTILINE)Flags in the RegExp constructor
When building a pattern dynamically, pass flags as the second argument:
function findAll(text, term) {
const re = new RegExp(term, 'gi');
return text.match(re) || [];
}Flag quick reference
| Flag | Effect |
|---|---|
i | Case-insensitive matching |
g | Find all matches, not just the first |
m | ^/$ match line starts/ends (not just string start/end) |
s | Dotall — . also matches \n |
u | Full Unicode mode |
x | Verbose mode with whitespace/comments (Python/Ruby, not JS) |
Where to go next
Next: common patterns — a practical catalogue of real-world patterns for emails, URLs, dates, numbers, and more.
Groups and alternation
Use parentheses to group sub-patterns for quantifiers and the pipe operator to match one of several alternatives.
Common patterns
A practical catalogue of real-world regex patterns for emails, URLs, dates, phone numbers, and more — with honest caveats about what regex can and cannot do.