3

I promise you I am not lying. There is one strange line in this userscript. Its

if(rePrv.test(h)||rePrv.test(h))

Now if i only have if(rePrv.test(h)) I sometimes get a false (incorrectly). However with the || i get the correct results. Its blowing my brain. What is going on? Can someone explain? It happens in under firefox 8, 11(portable) and chrome 17.0.

This is my userscript code.

// ==UserScript==
// @require         http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
// ==/UserScript==

var re=/\/?docs\/\d+/gi;
var rePrv=/\/?docs\/\d+\/private/gi;
var prvls="";
var publs="";
$('a').each(function(i, e){
    var h = $(this).attr('href');
    if(h==undefined)
        return;
    if(re.test(h)){
        if(rePrv.test(h)||rePrv.test(h)){
            prvls+="http://www.domain.com/"+h+"<br/>\n";
        }
        else {
            publs+="http://www.domain.com/"+h+"<br/>\n";
        }
    }
});

1 Answers1

4

Each instance of RegExp has an internal state, e. g. lastIndex that specifies the index at which to start the next match. If you call exec or any other method that uses exec internally like test does, that state might change when using global matching. So calling test multiple times can get you different results on each call:

var str = 'foobar foobar';
var re = /foo/g;
alert(re.test(str) && re.lastIndex);  // re.lastIndex === 3
alert(re.test(str) && re.lastIndex);  // re.lastIndex === 10
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • but thats still f'd. I'm trying to get a reproducible. This is... messed up. –  Mar 25 '12 at 12:30
  • @acidzombie24 It is reproducible. – Gumbo Mar 25 '12 at 12:34
  • @acidzombie24, just remove the `/g`. Why do you even have it there? – Qtax Mar 25 '12 at 12:42
  • ohhhh i'm still confused. Removing g did fix it but why did that affect anything? I mean why does the lastIndex carry onto the next test()? I forgot why but using /g became a habit. Maybe multiline replace? i'm not sure –  Mar 25 '12 at 12:46
  • @acidzombie24, *"why does the lastIndex carry onto the next test()?"* Because you use `/g`. – Qtax Mar 25 '12 at 13:03
  • @Qtax and Gumbo. I think i may have misunderstood `/g` into search/test across newlines. I had no idea it affected lastIndex. What does `/g` actually do? 'Global Search' doesnt help. –  Mar 25 '12 at 13:13
  • @acidzombie24 Global matching means to get all matches when used with `match`: `'foo'.match(/\w/g)` returns an array of all matches (`['f','o','o']`) while `'foo'.match(/\w/)` returns only the first match (`['f']`, but might as well contain the subpattern matches). – Gumbo Mar 25 '12 at 15:28
  • @Gumbo: Ok but... what does that have anything to do with the problem (lastIndex being affected across calls). Thats the biggesting wtf for me and isnt mentioned or explained anywhere! How is that even a feature/problem/side effect –  Mar 25 '12 at 15:46
  • @acidzombie24 How is what a feature/problem/side effect? The global matching? Or that there needs to be some kind of state maintained to know where the next search has to be started? – Gumbo Mar 25 '12 at 15:57
  • @Gumbo: I kind of assumed that an iterator/object will be returned and other calls on match would use that? Actually doesn't it return an array of matches? -looks up- yep http://www.w3schools.com/jsref/jsref_match.asp So why the heck is test() saving state when match doesn't appear to do so. wtf? Does anything actually use the state across calls? Now it appears to be there to make users mad. I don't remember anything that uses state across calls. Replace doesn't either http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_replace3 (it replaces all at once). What the heck DOES use state? –  Mar 26 '12 at 00:17
  • @acidzombie24 It’s the regular expression object itself that holds the state. `match`, `test`, and others that use `exec` just return the result(s) of the next matching attempt beginning at `lastIndex` which is `-1` initially. It is primarily used internally or when you use the fundamental `exec` function yourself as `exec` does only look for the next match and requires `lastIndex` for global matching. – Gumbo Mar 26 '12 at 18:05