Regex Sticky Flag
Regular Expressions: Regex Sticky Flag
What is the purpose of the sticky flag in JavaScript Regex?
View Answer:
let str = 'let varName = "value"';
let regexp = /\w+/y;
regexp.lastIndex = 3;
alert(regexp.exec(str)); // null (there's a space at position 3, not a word)
regexp.lastIndex = 4;
alert(regexp.exec(str)); // varName (word at position 4)
How does the sticky flag differ from the global flag?
View Answer:
1. Global flag (g): When the g
flag is used, the regular expression will be tested against all possible matches in a string. This is in contrast to the default behavior, which is to stop after the first match.
Here's an example:
let regex = /abc/g;
let str = 'abc abc abc';
let matches = str.match(regex);
console.log(matches); // Outputs: [ 'abc', 'abc', 'abc' ]
2. Sticky flag (y): The y
flag makes a regular expression "sticky", meaning it will only search for a match at the exact index where the previous match ended, instead of searching the entire string.
Here's an example:
let regex = /abc/y;
let str = 'abcabcabc';
let match = regex.exec(str);
console.log(match); // Outputs: [ 'abc', index: 0, input: 'abcabcabc', groups: undefined ]
match = regex.exec(str);
console.log(match); // Outputs: [ 'abc', index: 3, input: 'abcabcabc', groups: undefined ]
In this example, you can see that the exec()
method returns the next match each time it is called. This is because the y
flag causes the regex engine to search for a match only from the exact spot where the last match ended.
Another example to highlight the difference:
let str = 'abc xyz abc';
let regexGlobal = /abc/g;
let regexSticky = /abc/y;
console.log(regexGlobal.test(str)); // Outputs: true
console.log(regexGlobal.test(str)); // Outputs: true
console.log(regexSticky.test(str)); // Outputs: true
console.log(regexSticky.test(str)); // Outputs: false
In the case of the regexGlobal
, both tests return true
because after the first match, it continues searching for the next match from where it left off.
However, in the case of regexSticky
, the second test returns false
because it tries to match the pattern at the exact position following the first match (which is a space character in this case) and fails to find the pattern 'abc' there.
The sticky
flag can be very useful when you're parsing tokens in order or performing search-and-replace operations that should maintain state across multiple operations.
What does the "lastIndex" property represent in Regex with a sticky flag?
View Answer:
let regex = /abc/y;
let str = 'abcabcabc';
regex.lastIndex = 0;
console.log(regex.exec(str)); // Outputs: [ 'abc', index: 0, input: 'abcabcabc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 3
console.log(regex.exec(str)); // Outputs: [ 'abc', index: 3, input: 'abcabcabc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 6
In this example, you can see that lastIndex
starts at 0, and after each exec
call, it is updated to the position following the last match. Because the y
flag is set, each exec
call only looks for a match starting at lastIndex
.
If we set lastIndex
to a value that doesn't correspond to the start of a match, exec
will return null and lastIndex
will be reset to 0:
regex.lastIndex = 1;
console.log(regex.exec(str)); // Outputs: null
console.log(regex.lastIndex); // Outputs: 0
In the example above, because 'abc' doesn't start at index 1, the exec
method returned null and lastIndex
was reset to 0.
Is the sticky flag compatible with all browsers?
View Answer:
The sticky flag y
in regular expressions is a fairly modern feature in JavaScript and as of my last training cut-off in September 2021, it is supported in the following major browsers:
Browser | Version that added y flag support |
---|---|
Chrome | 49 |
Firefox | 3 |
Safari | 10 |
Edge | 15 |
Internet Explorer | Not supported |
Opera | 36 |
It is always a good idea to check the most recent compatibility information from a reliable source like Can I use or MDN Web Docs, as browser capabilities are constantly being updated.
Can you combine the sticky 'y' flag with other flags?
View Answer:
You can combine the y
flag with any other flags based on your requirement.
let regex = /abc/iy; // Case-insensitive and sticky
let str = 'ABCabcabc';
console.log(regex.exec(str)); // Outputs: [ 'ABC', index: 0, input: 'ABCabcabc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 3
Please note that the order of the flags doesn't matter. /abc/iy
is the same as /abc/yi
.
What happens if the sticky flag 'y' doesn't find a match at the "lastIndex"?
View Answer:
Here is a JavaScript code example demonstrating what happens when a sticky flag regex does not find a match at the position specified by lastIndex
.
let regex = /abc/y;
let str = 'abc def abc';
console.log(regex.exec(str)); // Outputs: [ 'abc', index: 0, input: 'abc def abc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 3
console.log(regex.exec(str)); // Outputs: null
console.log(regex.lastIndex); // Outputs: 0
How does the sticky flag 'y' affect the "exec" method?
View Answer:
let regex = /abc/y; // sticky regex
let str = 'abcabcabc';
console.log(regex.exec(str)); // Outputs: [ 'abc', index: 0, input: 'abcabcabc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 3 (updated to the position following the match)
console.log(regex.exec(str)); // Outputs: [ 'abc', index: 3, input: 'abcabcabc', groups: undefined ]
console.log(regex.lastIndex); // Outputs: 6 (updated to the position following the match)
regex.lastIndex = 7; // set lastIndex to a position where there's no 'abc'
console.log(regex.exec(str)); // Outputs: null (no match found at lastIndex)
console.log(regex.lastIndex); // Outputs: 0 (reset to 0)
What does the sticky flag 'y' do with the "match" method?
View Answer:
// you must add the 'g' global flag or it will result in an Type error
let regex = /abc/gy;
let str = 'abcabcabc';
let matches = str.matchAll(regex);
for (let match of matches) {
console.log(match);
}
// Outputs:
// [ 'abc', index: 0, input: 'abcabcabc', groups: undefined ]
// [ 'abc', index: 3, input: 'abcabcabc', groups: undefined ]
// [ 'abc', index: 6, input: 'abcabcabc', groups: undefined ]
The Official ECMA Specification, ECMA-262 as of February 15, 2020, states that if there is no g flag present, that matchAll should throw a TypeError. ( See here https://tc39.es/ecma262/#sec-string.prototype.matchall )
What is a common use case for the sticky flag 'y'?
View Answer:
let input = 'a,b,c';
let regex = /([^,]+),?/y; // match one or more non-comma characters, followed by optional comma
let match;
let output = [];
while (match = regex.exec(input)) {
output.push(match[1]); // push the captured group
}
console.log(output); // Outputs: [ 'a', 'b', 'c' ]