15.5.4.11 String.prototype.replace(searchValue, replaceValue)

2010-07-10

string String.prototype.replace(searchValue:string|regexp|mixed, replaceValue:string|function|mixed)

Replace this string value by replacing all occurrences of the string or matches of the regular expression by either the second string parameter or by the string result of calling the second function parameter.

Note that this is NOT a global match by default. That means it will not replace ALL occurrences by default. You will need to supply a regular expression WITH global flag for that to happen. Only then will all occurrences be replaced.

The this value is coerced to a string.

The searchValue can be a regular expression (an object having [[Class]] set to "RegExp"). In that case it either replaces a single occurrence if the global property is false, or all occurrences if global is true. It uses the same principle as String.prototype.match (15.5.4.10) for it (also using the lastIndex property to track).

It also checks the number of capturing parentheses in searchValue (15.10.2.1).

If searchValue is not a regular expression it is coerced to a string.

If replaceValue is a function it will be called for each match. The number of parameters is equal to 3 plus the number of capturing groups. The first arguments will be the matches from these groups (see MatchResult, 15.10.2.1). The last three are always given. The first (of the three) is the matched string, the second is position where the match starts and the third is the string currently being searched. The callback should return a string (it will be coerced into one) which will be the replacement value for (and only for) the matched substring.

Otherwise replaceValue will be coerced to a string. For each match, the coerced string will have certain dollar tokens replaced by specified values (see below). The result of doing so will be the value by which the match is replaced. If a dollar was found but not a defined token the dollar is left as is. The replaced values are NOT searched again.
- $$ becomes $
- $& becomes the matched substring
- $` becomes the part of the string before the matched substring
- $’ becomes the part of the string after the matched substring
- $n becomes the nth captured group. n can be 1..9 and may not be followed by another digit (see next item)
- $nn becomes the nnth capture group. n can be 01..99 and will be the empty string if nothing was captured.

The algorithm wasn't given explicitly but it will go something like this.

Code: (Meta Ecma)
String.prototype.replace = function(searchValue, replaceValue){
CheckObjectCoercible(this);
var string = ToString(this);

if (Type(searchValue) == "Object" && searchValue.[[Class]] == "RegExp") {
var global = search.[[Get]]("global");
// now we need to collect all matches, including the offset and the matched string per match
// because we might need to feed it to a callback later, or replace dollar sign tokens with them

// todo: this is the same as match, except index is also tracked
var matches = [{match:string, index:int}, ...];

// now we get the number of capturing groups, like 15.10.2.1
var m = NcaptuingParens(searchValue); // todo
} else {
var searchString = ToString(searchValue);
var pos = string.indexOf(searchString);
var matches = [{match:searchString, index:pos}];
var m = 0;
}

if (Type(replaceValue) == 'Object' && replaceValue.[[Class]] == "Function") {
// call replaceValue with one parameter for each capturing group, the match, the position and the source
var a = new Array(m); // todo: this array should be the captured results from capturing groups
for (var i=0; i a.slice().push(matches[i ].match, matches[i ].index, string);
var result = replaceValue.apply(undefined, a); // context is undefined...
result = ToString(result);
// now replace the match by the result
string = string.substr(0, matches[i ].index)+result+string.substr(matches[i ].index+matches[i ].match.length);
}
} else {
var newstring = ToString(replaceValue);

// search for the positions of all dollar tokens that will be replaced in the loop
var dollars = new Array; // todo, find all occurrences of $

// now replace each match by newstring, after (for each individual match) the
// occurrence of certain dollar tokens have been replaced by match specific data
for (var i=0; i var newnewstring = newstring;
// replace all dollar tokens by certain values as per specification
newnewstring = // todo :)
// use the result to replace the searchValue
string = string.substr(0, matches[i ].index)+newnewstring+string.substr(matches[i ].index+matches[i ].match.length);
}
}
return string;
}