I've just notice a strange JS behavior that lead to an annoying bug..
Basically, I test a str with a RegExp object (.test() method) in a if statement. For the same string tested, if in my code I have only a if, the regexp.test() return true and it goes fine into the if.
The problem is if I had a else (and I need it), for some reason, for the same str tested, the regexp.test() returns false and it goes to the else...
What is this behavior ?
I have run many tests...
TL/DR : For the same string tested on the same RegExp, if there is only a IF statement the regexp.test() returns true, but if I had a else it returns false.
some code
I forgot to say that the bug doesn't occurs with all words..
http://jsfiddle.net/zrwkU/13/
Write the word "armoire" in the text field and press enter. This jsfiddle has the "else return false" and nothing happens.
Remove the "else return false" in the searchDeeper function ( if (regexp.test(tested)){ ) and do the test again. Now it goes into the if and a msgbox popup.
With patterns having the global 'g'
flag set, the RegExp
methods; test()
and exec()
keep track of the last place they matched and store this integer number in the RegExp object's: lastIndex
property. This index is automatically advanced as each match is applied to any string. Note that both test()
and exec()
behave this way. Once any match fails, this last index property is automatically reset to zero. You can manually reset it to zero yourself, too, and it sure looks like that's what you need to do here. Add a line to reset RegExp.lastIndex
like so:
if (regexp != null){
regexp.lastIndex = 0;
if (regexp.test(tested)){
alert('ok');
regexp.lastIndex = 0;
var res = regexp.exec(tested);
tested = tested.replace(res, '<span class="underlined">' + res + '</span>');
}else{
return false;
}
}
Here is another solution which avoids this last-index-issue altogether. It uses the String.match()
method instead:
String.match()
alternative:if (regexp != null){
if (tested.match(regexp)){
alert('ok');
regexp.lastIndex = 0;
var res = tested.match(regexp);
tested = tested.replace(res, '<span class="underlined">' + res + '</span>');
}else{
return false;
}
}
I think the only issue is that where you have
}else{
return false;
}
What you actually want is
}else{
continue;
}
in order to continue the outer loop for (var k in cats){
.
As per this update: http://jsfiddle.net/zrwkU/14/
By way of explanation - with your code, as soon as a call to test
fails, thats it - out of the method you jump using return false
. By changing to a continue
you continue to "search deeper" in other categories too.
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