Why Does a Regexp With Global Flag Give Wrong Results

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 0s 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 the g flag, if you use it with RegExp#test(), you must not use g 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 0s 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:

  1. Let match be the result of evaluating the RegExp.prototype.exec (15.10.6.2) algorithm upon this RegExp object using string as the argument.
  2. If match is not null, then return true; else return false.

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



Leave a reply



Submit