Why does a RegExp with global flag give wrong results?
A RegExp
object with the g
flag keeps track of the lastIndex
where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:
var query = 'Foo B';
var re = new RegExp(query, 'gi');
console.log(re.lastIndex);
console.log(re.test('Foo Bar'));
console.log(re.lastIndex);
console.log(re.test('Foo Bar'));
console.log(re.lastIndex);
Why does the 'g' flag change the result of a JavaScript regular expression?
In JavaScript, regular expression objects have state. This matters when the g
flag ("global") is applied to them, and sometimes applies in odd ways. This state is the index where the match last occurred, which is the regex's .lastIndex
property. When you call exec
or test
on the same regex object again, it picks up from where it left off.
What's happening in your example is for the second call, it's picking up where it left off the last time, and so it's looking starting after the 10th character in the string — and doesn't find a match there, because there's no text there at all (and even if there were, the ^
assertion wouldn't match).
We can see what's happening if we look at the lastIndex
property:
var reg = new RegExp("^19[-\\d]*","g");
snippet.log("Before first test: " + reg.lastIndex);
snippet.log(reg.test('1973-02-01')); //return true
snippet.log("Before second test: " + reg.lastIndex);
snippet.log(reg.test('1973-01-01')); //return false
snippet.log("After second test: " + reg.lastIndex);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Why regExp test with flag 'g' return wrong value?
See this documentation.
If the regex has the global flag set, test() will advance the lastIndex of the regex. A subsequent use of test() will start the search at the substring of str specified by lastIndex (exec() will also advance the lastIndex property).
Why does javascript RegExp test function give different result each time when used with flags?
The g
flag tells the RegExp
object to remember the position of the last match and resume from there the next time a match (or test, in this case) is attempted.
global Regexp is returning incorrect index inside for loop
There are quite a few issues here:
- You get
0
s because your regex does not match, and it does not match because you defined the regex string inside a regular string literal, thus, losing all single backslashes. The pattern must be set with a regex literal,let globalRegex = /^\d+\-\d+$/;
(see Why this javascript regex doesn't work?). Note the absence of theg
flag, if you use it withRegExp#test()
, you must not useg
flag to avoid issues (see Why does a RegExp with global flag give wrong results?). - Even if you define the regex properly you will get
0
s as output because a/^\d+\-\d+$/
regex can and will only match at the start of the string (Index=0). You seeem to want to get the IDs of the "words" or "tokens" in the string, so you need to count them.
So, you could re-write the code as
for(let filename of ["123-123_aaa_bbb_ccc","aaa_bbb_ccc_129-999"])
{
let result = -1;
let s=filename.split("_")
let globalRegex = /^\d+\-\d+$/;
for (const [index, si] of s.entries()) {
if(globalRegex.test(si)) {
result = index
break
}
}
console.log(`match found at: `, result)
}
Why does the g modifier give different results when test() is called twice?
To workaround the problem, you can remove the g
flag or reset lastIndex
as in
var reg = /a/g;
console.log(reg.test("a"));
reg.lastIndex = 0;
console.log(reg.test("a"));
The problem arises because test
is based around exec
which looks for more matches after the first if passed the same string and the g
flag is present.
15.10.6.3
RegExp.prototype.test(string)
# Ⓣ ⓇThe following steps are taken:
- Let match be the result of evaluating the
RegExp.prototype.exec
(15.10.6.2) algorithm upon thisRegExp
object using string as the argument.- If match is not
null
, then returntrue
; else returnfalse
.
The key part of exec
is step 6 of 15.10.6.2:
6. Let global be the result of calling the [[Get]] internal method of R with argument "global".
7. If global is false, then let i = 0.
When i
is not reset to 0, then exec
(and therefore test
) does not start looking at the beginning of the string.
This is useful for exec
because you can loop to handle each match:
var myRegex = /o/g;
var myString = "fooo";
for (var match; match = myRegex.exec(myString);) {
alert(match + " at " + myRegex.lastIndex);
}
but obviously it isn't so useful for test
.
javascript regex globally case insensitive issue
Just use String.search
or String.match
instead of test
:
const TicketNumbers = ['ex1', '2eX', '3Ex4', '5EX6', 'foo']
const exPrefix = /ex/ig;
const exTickets = TicketNumbers
.filter(ticket => ticket.search(exPrefix) >= 0)
.map(t => t.replace(exPrefix, ''))
console.log(exTickets)
Why is Regex Javascript //g flag affecting state?
When you use the global flag in the regex, the lastIndex property is updated. The lastIndex property is the index at which to start the next match.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp
You can reset the last index before calling again. See
Why RegExp with global flag in Javascript give wrong results?
why does my javascript regex.test() give alternating results
When you're using /g
, the regex object will save state between calls (since you should be using it to match over multiple calls). It matches once, but subsequent calls start from after the original match.
(This is a duplicate of Javascript regex returning true.. then false.. then true.. etc)
Related Topics
Parsing a String to a Date in JavaScript
What Is Jsonp, and Why Was It Created
Loop Through an Array in JavaScript
Remove Duplicate Values from Js Array
Merge/Flatten an Array of Arrays
Firebase Query If Child of Child Contains a Value
"Cross Origin Requests Are Only Supported For Http." Error When Loading a Local File
How to Use a Variable in a Regular Expression
What Is the !! (Not Not) Operator in JavaScript
Test For Existence of Nested JavaScript Object Key
Is There a JavaScript/Jquery Dom Change Listener
What's the Meaning of "=≫" (An Arrow Formed from Equals & Greater Than) in JavaScript
How to Check If Element Is Visible After Scrolling
How to Group an Array of Objects by Key
How to Attach Events to Dynamic HTML Elements With Jquery