es-shims/es5-shim

regex lastIndex

espretto opened this issue · 5 comments

the regex lastIndex bug seems to persist although es5shim is included.

var empty = ''
var re = /.*/g
re.exec(empty)
re.lastIndex === 0 // false in IE6

I've seen this is being worked around to patch String#replace but RegExp#exec is none the wiser.

Indeed, I see that in IE 6, 7, and 8, var re = /.*/g; alert(re.lastIndex); re.exec(''); alert(re.lastIndex); alerts 0/1, whereas in IE 9 and everything else, it alerts 0/0.

I'll look into this; thanks for the report!

@espretto where do you see this being worked around with String#replace? We're only patching it if the function form reports capture groups incorrectly.

my mistake, it wasn't String#replace but String#split when using regular expressions. here you can find the exact line: lastIndex = match.index + match[0].length. I cannot attest whether it's the same bug being worked around though.

Thanks, I'll see what I can do.

This seems like it's only a bug when exec is given an empty string, no?

unfortunately, i've seen this bug occur on non-empty strings, too. i think the question is whether or not the regex matches zero or more of something. for example this yields different results, too:

var re = /[a-z]*/g
re.lastIndex = 1
re.exec('s')
re.lastIndex === 2 // in IE6, expected empty string match at pos 1 instead
re.lastIndex = 1
re.exec('s1')
re.lastIndex === 2 // in IE6, expected empty string match at pos 1 instead

for a patch i'm thinking (not tested):

var hasLastIndexBug = (function () {
  var re = /.*/g
  re.exec('')
  return re.lastIndex !== 0
}())

if (hasLastIndexBug) {
  var nativeExec = RegExp.prototype.exec
  RegExp.prototype.exec = function exec (string) {
    var match = nativeExec.call(this, string)
    if (match && !match[0].length) this.lastIndex--
    /* or alternatively
    if (match && !match[0].length) this.lastIndex = match.index
     * or most explicit
    if (match && !match[0].length) this.lastIndex = match.index + match[0].length
     */
    return match
  }
}

it seems the state-machine forgets to reset its look-ahead pointer before it bails out.