String#replace String#match and regexp.lastIndex

View: New views
6 Messages — Rating Filter:   Alert me  

String#replace String#match and regexp.lastIndex

by jdalton-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I noticed in the ECMA 5 draft that String#replace references
String#match's handling of regexp.lastIndex
when the regexp is flagged global. According to the draft String#match
sets the regexp.lastIndex when the regexp is global.
Currently Firefox, Chrome, Safari, Opera do not set the lastIndex on
String#match or String#replace.
IE does set the lastIndex but only once, not during each internal
iteration of `Repeat, while lastMatch is true`, and for non-global
regexp's as well.

According to spec I would expect:

var s = '0x2x4x6x8';
var p = /x/g;
s.replace(p, function() { alert(p.lastIndex)  }); // A: alerts 2, then
4, then 6, then 8
alert(p.lastIndex); // B: alerts 0 because internal exec returned null
(which set lastIndex 0) triggering the end of the iteration;

// IE7
// A: alerts 0, then 0, then 0, then 0
// B: alerts 8

// All others
// A: alerts 0, then 0, then 0, then 0
// B: alerts 0

This might be a compatibility issue to consider.


- John-David Dalton
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: String#replace String#match and regexp.lastIndex

by StevenLevithan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> I noticed in the ECMA 5 draft that String#replace references
> String#match's handling of regexp.lastIndex
> when the regexp is flagged global. According to the draft String#match
> sets the regexp.lastIndex when the regexp is global.

All of this is identical to ECMA-262 Edition 3.

> Currently Firefox, Chrome, Safari, Opera do not set the lastIndex on
> String#match

Yes they do. Leaving aside whatever happens during the matching process
(since it's unobservable to users), String#match called with a "global"
RegExp always starts searching from index 0 and the RegExp's lastIndex is
always 0 after after the method is complete. (That is, except in IE, which
has the bug you mentioned where lastIndex is not always 0 after a match or
replace using a "global" regex is complete.)

This should alert 0, demonstrating that the browsers you mentioned do update
lastIndex:

var x = /x/g;
x.lastIndex = 1;
"x123x5".match(x);
alert(x.lastIndex);

> or String#replace.
> IE does set the lastIndex but only once, not during each internal
> iteration of `Repeat, while lastMatch is true`, and for non-global
> regexp's as well.
>
> According to spec I would expect:
>
> var s = '0x2x4x6x8';
> var p = /x/g;
> s.replace(p, function() { alert(p.lastIndex)  }); // A: alerts 2, then
> 4, then 6, then 8
> alert(p.lastIndex); // B: alerts 0 because internal exec returned null
> (which set lastIndex 0) triggering the end of the iteration;
>
> // IE7
> // A: alerts 0, then 0, then 0, then 0
> // B: alerts 8
>
> // All others
> // A: alerts 0, then 0, then 0, then 0
> // B: alerts 0

Opera 9.64 (and other versions I've previously tested this issue with)
alerts A: 2, 4, 6, 8 and B: 0. Like you, this is my interpretation of
correct handling according to the spec. Opera tends to follow the spec most
closely for regex issues, in general.

> This might be a compatibility issue to consider.

Sure, but it's a decade old.

Steve
--------------------
Steven Levithan
Baghdad, Iraq
http://blog.stevenlevithan.com
 

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: String#replace String#match and regexp.lastIndex

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 1, 2009, at 10:08 AM, Steve L. wrote:

> Opera 9.64 (and other versions I've previously tested this issue  
> with) alerts A: 2, 4, 6, 8 and B: 0. Like you, this is my  
> interpretation of correct handling according to the spec. Opera  
> tends to follow the spec most closely for regex issues, in general.

This seems like a bug for other vendors than Opera to fix. Filed:

https://bugzilla.mozilla.org/show_bug.cgi?id=501739

I suspect no one will mind the fix, and a few will welcome it. But we  
will have to try it out on real developers and users to be sure.

/be
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: String#replace String#match and regexp.lastIndex

by jdalton-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

@Steve - You are correct about Opera and about other browsers use of
String#match.
I must have been using an invalid test at the time. Thanks for the
additional info.

@Brendan - Thanks for creating the bug report :D
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: String#replace String#match and regexp.lastIndex

by StevenLevithan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

It may be beneficial to clarify in the ES5 spec that searches should take
place and lastIndex should be updated based on a copy of the value of
lastIndex made at the start of String#replace's processing. If you follow
the dependency chain--where String#replace relies on the definition of
String#match, which in turn relies on RegExp#exec--it looks to me like the
spec requires this code to become an infinite loop:

var str="0x2x3", a=["x","y","z"], i=0, re=/x/g;
alert(str.replace(re, function(){
    re.lastIndex = 0;
    return a[i++];
}));

However, it is not an infinite loop in 5 out of 5 browsers. It should also
be unambiguous that this would alert "0x2y3" (as it does in all the big
browsers) and not "0y2z3".

While we're discussing String#replace, is it too late to formally spec what
$n and $nn in replacement strings should mean when n is greater than the
number of capturing groups within the regex? ES 3 & 5-draft say this is
implementation-defined. Firefox 3.5, IE 8, Safari 4, Chrome 2, Opera 9.64,
and all other browsers I've tested with say that e.g. "test".replace(/(e)/,
"$2") returns "t$2st". I rely on this behavior, and I may not be the only
one.

Steve
--------------------
Steven Levithan
Baghdad, Iraq
http://blog.stevenlevithan.com
 

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: String#replace String#match and regexp.lastIndex

by StevenLevithan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

It may be beneficial to clarify in the ES5 spec that searches should take
place and lastIndex should be updated based on a copy of the value of
lastIndex made at the start of String#replace's processing. If you follow
the dependency chain--where String#replace relies on the definition of
String#match, which in turn relies on RegExp#exec--it looks to me like the
spec requires this code to become an infinite loop:

var str="0x2x3", a=["x","y","z"], i=0, re=/x/g;
alert(str.replace(re, function(){
    re.lastIndex = 0;
    return a[i++];
}));

However, it is not an infinite loop in 5 out of 5 browsers. It should also
be unambiguous that this would alert "0x2y3" (as it does in all the big
browsers) and not "0y2z3".

While we're discussing String#replace, is it too late to formally spec what
$n and $nn in replacement strings should mean when n is greater than the
number of capturing groups within the regex? ES 3 & 5-draft say this is
implementation-defined. Firefox 3.5, IE 8, Safari 4, Chrome 2, Opera 9.64,
and all other browsers I've tested with say that e.g. "test".replace(/(e)/,
"$2") returns "t$2st". I rely on this behavior, and I may not be the only
one.

Steve
--------------------
Steven Levithan
Baghdad, Iraq
http://blog.stevenlevithan.com
 

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss