Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the 'y' sticky pattern modifier in JavaScript RegExps?

MDN introduced the 'y' sticky flag for JavaScript RegExp. Here is a documentation excerpt:

y

sticky; matches only from the index indicated by the lastIndex property of this regular expression in the target string (and does not attempt to match from any later indexes).

There's also an example:

var text = 'First line\nSecond line';
var regex = /(\S+) line\n?/y;

var match = regex.exec(text);
console.log(match[1]);        // prints 'First'
console.log(regex.lastIndex); // prints '11'

var match2 = regex.exec(text);
console.log(match2[1]);       // prints 'Second'
console.log(regex.lastIndex); // prints '22'

var match3 = regex.exec(text);
console.log(match3 === null); // prints 'true'

But there isn't actually any difference between the usage of the g global flag in this case:

var text = 'First line\nSecond line';
var regex = /(\S+) line\n?/g;

var match = regex.exec(text);
console.log(match[1]);        // prints 'First'
console.log(regex.lastIndex); // prints '11'

var match2 = regex.exec(text);
console.log(match2[1]);       // prints 'Second'
console.log(regex.lastIndex); // prints '22'

var match3 = regex.exec(text);
console.log(match3 === null); // prints 'true'

Same output. So I guess there might be something else regarding the 'y' flag and it seems that MDN's example isn't a real use-case for this modifier, as it seems to just work as a replacement for the 'g' global modifier here.

So, what could be a real use-case for this experimental 'y' sticky flag? What's its purpose in "matching only from the RegExp.lastIndex property" and what makes it differ from 'g' when used with RegExp.prototype.exec?

Thanks for the attention.

like image 903
tonix Avatar asked May 17 '15 19:05

tonix


2 Answers

The difference between y and g is described in Practical Modern JavaScript:

The sticky flag advances lastIndex like g but only if a match is found starting at lastIndex, there is no forward search. The sticky flag was added to improve the performance of writing lexical analyzers using JavaScript...

As for a real use case,

It could be used to require a regular expression match starting at position n where n is what lastIndex is set to. In the case of a non-multiline regular expression, a lastIndex value of 0 with the sticky flag would be in effect the same as starting the regular expression with ^ which requires the match to start at the beginning of the text searched.

And here is an example from that blog, where the lastIndex property is manipulated before the test method invocation, thus forcing different match results:

var searchStrings, stickyRegexp;

stickyRegexp = /foo/y;

searchStrings = [
    "foo",
    " foo",
    "  foo",
];
searchStrings.forEach(function(text, index) {
    stickyRegexp.lastIndex = 1;
    console.log("found a match at", index, ":", stickyRegexp.test(text));
});

Result:

"found a match at" 0 ":" false
"found a match at" 1 ":" true
"found a match at" 2 ":" false
like image 71
Wiktor Stribiżew Avatar answered Nov 18 '22 11:11

Wiktor Stribiżew


There is definitely a difference in behaviour as showed below:

var text = "abc def ghi jkl"
undefined
var regexy = /\S(\S)\S/y;
undefined
var regexg = /\S(\S)\S/g;
undefined
regexg.exec(text)
Array [ "abc", "b" ]
regexg.lastIndex
3
regexg.exec(text)
Array [ "def", "e" ]
regexg.lastIndex
7
regexg.exec(text)
Array [ "ghi", "h" ]
regexg.lastIndex
11
regexg.exec(text)
Array [ "jkl", "k" ]
regexg.lastIndex
15
regexg.exec(text)
null
regexg.lastIndex
0
regexy.exec(text)
Array [ "abc", "b" ]
regexy.lastIndex
3
regexy.exec(text)
null
regexy.lastIndex
0

..but I have yet to fully understand what is going on there.

like image 20
tato Avatar answered Nov 18 '22 13:11

tato