I'd like to search a string for several matches. Each match is eventually linked to an object property in an object array. When a match is found, that match is replaced by another property within an object. The problem is the code will always return null on the second match.
This is the test case that I am using. To simplify the problem, I just replace all matches with the number 5, but note that the final code will be replacing the match with a variable value.
Below is the code I'm using to test and debug the issue. The interesting thing is that if I change var str = '5 + QUESTION_2'
, QUESTION_2
is successfully replaced with 5. Essentially, the problem boils down to the second match always returning null even though it can be matched.
var re = /( |^)(QUESTION_1|QUESTION_2|QUESTION_3)( |$)/g;
var str = 'QUESTION_1 + QUESTION_2';
var rep = 5;
matches = re.exec(str);
var re2 = new RegExp("( |^)(" + matches[2] + ")( |$)", "g");
console.log(matches); // Returns a match on QUESTION_1
str = str.replace(re2, rep);
console.log(str); // Returns 5+ QUESTION_2
matches = re.exec(str);
console.log(matches); // Returns a match on NULL - doesn't find QUESTION_2
re2 = new RegExp("( |^)(" + matches[2] + ")( |$)", "g");
str = str.replace(re2, rep);
console.log(str); // Returns 5+ QUESTION_2
JavaScript RegExp exec() The exec() method tests for a match in a string. If it finds a match, it returns a result array, otherwise it returns null.
exec() The exec() method executes a search for a match in a specified string and returns a result array, or null .
The difference in between exec() and test() method is that the exec() method will return the specified match if present or null if not present in the given string whereas the test() method returns a Boolean result i.e., true if the specified match is present or else returns false if it is not present.
Since you're using global flag in exec call regex engine remembers lastIndex which is is a read/write integer property of regular expressions that specifies the index at which to start the next match.
Place this to reset it:
re.lastIndex=0;
Just before next call to RegExp.exec
re.lastIndex = 0
allows you to reset the search index to perform a second search starting from the beginning. Without it, the search begins at the index of the last match, which would yield null
in this case.
Read this Mozilla doc for more info on this. As per this manual:
This property is set only if the regular expression used the "g" flag to indicate a global search.
When calling exec on a global regex, it remembers where was the last match and starts the next one from there.
var rx = /a/g, matches = rx.exec('aa');
rx.lastIndex; //1
When you modify your input string, between exec
calls, the lastIndex
becomes desychronised.
While there's a few way to fix this, I would rather perform the replace in a single statement.
'QUESTION1 + QUESTION2 + QUESTION3'.replace(/QUESTION\d+/g, function ($1) {
return 'VALUE_FOR_' + $1;
});
//"VALUE_FOR_QUESTION1 + VALUE_FOR_QUESTION2 + VALUE_FOR_QUESTION3"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With