JavaScript Regex Sticky Flag Explained
This article explores the sticky flag (y) in JavaScript
regular expressions, detailing how it functions, how it differs from the
global flag (g), and when to use it. You will learn how the
sticky flag forces a pattern to match strictly at the regex’s
lastIndex position without searching forward, making it an
essential tool for parsing text and building tokenizers efficiently.
What is the Sticky Flag?
The sticky flag, denoted by the character y, is a
modifier applied to a regular expression (for example,
/pattern/y or new RegExp('pattern', 'y')).
When the sticky flag is active, a regular expression will attempt to
match a target string only at the index specified by
the lastIndex property of the RegExp instance. Unlike
standard regular expression searches that scan forward through the
string until they find a matching sequence, a sticky regex must match
immediately at lastIndex. If no match exists at that exact
position, the match fails and lastIndex resets to
0.
How the Sticky Flag Works
By default, the lastIndex property of a regular
expression starts at 0. When using methods like
RegExp.prototype.exec() or
RegExp.prototype.test(), the sticky flag alters search
behavior in the following ways:
- Exact Position Matching: The regex engine checks if
the pattern matches the substring starting precisely at
str[regex.lastIndex]. - Advancing
lastIndex: If a match is successful,regex.lastIndexis automatically updated to the index immediately following the matched text. - Immediate Failure: If the character at
regex.lastIndexdoes not begin the match, the method immediately returnsnull(orfalsefor.test()), andregex.lastIndexis reset to0.
Code Example
const text = "123 abc 456";
const stickyRegex = /\d+/y;
// First match: checks text starting at index 0 (match: "123")
console.log(stickyRegex.exec(text)[0]); // Output: "123"
console.log(stickyRegex.lastIndex); // Output: 3
// Second match: checks text starting at index 3 (which is a space " ")
// Since " " does not match \d+, the match fails immediately.
console.log(stickyRegex.exec(text)); // Output: null
console.log(stickyRegex.lastIndex); // Output: 0If you manually set lastIndex to a position where a
match exists, the sticky regex succeeds:
const text = "123 abc 456";
const stickyRegex = /\d+/y;
stickyRegex.lastIndex = 8; // Index where "456" begins
console.log(stickyRegex.exec(text)[0]); // Output: "456"
console.log(stickyRegex.lastIndex); // Output: 11Sticky Flag (y)
vs. Global Flag (g)
While both the g and y flags retain state
across multiple .exec() or .test() calls by
using the lastIndex property, their matching strategies
differ fundamentally:
- Global Flag (
g): Searches the string starting atlastIndexand continues moving forward through subsequent characters until it finds a match. - Sticky Flag (
y): Searches only atlastIndex. It does not skip intervening characters to find a match further down the string.
const text = "apple 123";
const globalRegex = /\d+/g;
globalRegex.lastIndex = 0;
console.log(globalRegex.exec(text)[0]); // Output: "123" (scanned forward past "apple ")
const stickyRegex = /\d+/y;
stickyRegex.lastIndex = 0;
console.log(stickyRegex.exec(text)); // Output: null (stopped because index 0 is "a")Performance and Use Cases
The primary use case for the sticky flag is lexical analysis (lexing/tokenizing) in compilers, interpreters, and template engines.
When tokenizing code or structured text: * Characters must be parsed
in a strict sequential order without skipping unrecognized tokens. *
Using standard regexes often requires extracting substrings
(str.slice(i)) or prefixing patterns with the
start-of-input anchor ^, both of which can introduce memory
overhead and performance bottlenecks. * The sticky flag avoids substring
allocation and ensures linear-time matching directly against the target
string at the current parser offset.