Some time ago, my colleague “Barbie Q” had a problem with regular expressions.” Barbie Q” almost lost barbie Q because of this problem.

Here’s the problem

“Barbie Q” discovered that the same regular expression can return different values when processing the same string (O ω O ױ)!

const reg = /hello/g;
console.log(reg.test('hello')); // true
console.log(reg.test('hello')); // false
console.log(reg.test('hello')); // true
console.log(reg.test('hello')); // false
Copy the code

What’s the matter

After some cool analysis, “Barbie Q” decided that the “G” parameter in the expression was suspicious, so she decided to try it out

const reg = /hello/;
console.log(reg.test('hello')); // true
console.log(reg.test('hello')); // true
console.log(reg.test('hello')); // true
console.log(reg.test('hello')); // true
Copy the code

Finally, the output results are consistent and consistent with the expected, surprisingly, it is the thing caused by G, so why does this phenomenon occur after adding g flag parameter? Do other flag parameters cause similar problems? Barbie Q decided to find out.

To find out

We know that the g flag parameter is used for global search, usually in conjunction with the exec() method. Multiple matches can iterate over strings that match the regular expression, for example:

const reg = /(hello)/g;
const input = 'hello world, hello RegExp, I am babiQ';
let result;
while((result = reg.exec(input)) ! = =null) {
    console.log(` match to${result[0]}And the next position to start matching is${reg.lastIndex}`);
    // "Match to hello, next start match position is 5"
    // "Match to hello, next start match position is 18"
}
Copy the code

In this example, the lastIndex and g flag parameters are very closely related. You can see that the lastIndex value changes after each match because the RegExp object records the position of the last successful match in the lastIndex property. If the match fails, It resets lastIndex to 0.

With that background in mind, going back to the original problem, it’s because barbie Q is set to /g, so the lastIndex property records where the next match starts, resulting in this unexpected result:

const reg = /hello/g;
console.log(The initial value of lastIndex is${reg.lastIndex}`);
let result = reg.test('hello');
console.log('matching result is${result}, the lastIndex value is${reg.lastIndex}`);
result = reg.test('hello');
console.log('matching result is${result}, the lastIndex value is${reg.lastIndex}`);
result = reg.test('hello');
console.log('matching result is${result}, the lastIndex value is${reg.lastIndex}`);
result = reg.test('hello');
console.log('matching result is${result}, the lastIndex value is${reg.lastIndex}`);

// output:
// "lastIndex starts with 0"
// "Match result is true, lastIndex is 5"(after one match, lastIndex is 5, so the next match will start at subscript 5)
// "Match result is false, lastIndex is 0"(after a second match, the match starts at subscript 5, so lastIndex is reset to 0, next match starts at subscript 0)
// "the result is true, and the lastIndex value is 5"(after three matches, the match starts at 0, so the value is matched, so the next match starts at 5)
// "Match false, lastIndex = 0"
Copy the code

How to solve

In fact, the lastIndex attribute only works if the G flag argument is used.

Once again return to the problems in the “barbie Q”, “barbie Q” actually USES the regular just want to determine whether a string containing the hello string, if contain, go on to the next step of operation, in this case but don’t use/g are able to judge, but after using the/g also can cause unexpected results, Therefore, we need to think clearly when using g flag parameter:

  • Whether your regular expression really needs to use /g

  • If you do need /g, think about whether you need to reset lastIndex to 0 every time you use the test() method