Improve speed of String.replace by around 33% by not constructing
sliced strings for the interstices of the matches. This can be speeded up further. Review URL: http://codereview.chromium.org/13614 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@931 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
ba09ec5e89
commit
bf9d096326
@ -198,9 +198,9 @@ function StringReplace(search, replace) {
|
||||
if (start < 0) return subject;
|
||||
var end = start + search.length;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
var builder = new ReplaceResultBuilder(subject);
|
||||
// prefix
|
||||
builder.add(SubString(subject, 0, start));
|
||||
builder.addSpecialSlice(0, start);
|
||||
|
||||
// Compute the string to replace with.
|
||||
if (IS_FUNCTION(replace)) {
|
||||
@ -210,7 +210,7 @@ function StringReplace(search, replace) {
|
||||
}
|
||||
|
||||
// suffix
|
||||
builder.add(SubString(subject, end, subject.length));
|
||||
builder.addSpecialSlice(end, subject.length);
|
||||
|
||||
return builder.generate();
|
||||
}
|
||||
@ -234,18 +234,27 @@ function StringReplaceRegExp(subject, regexp, replace) {
|
||||
var length = matches.length;
|
||||
|
||||
// Build the resulting string of subject slices and replacements.
|
||||
var result = new StringBuilder();
|
||||
var result = new ReplaceResultBuilder(subject);
|
||||
var previous = 0;
|
||||
// The caller of StringReplaceRegExp must ensure that replace is not a
|
||||
// function.
|
||||
replace = ToString(replace);
|
||||
for (var i = 0; i < length; i++) {
|
||||
var captures = matches[i];
|
||||
result.add(SubString(subject, previous, captures[0]));
|
||||
ExpandReplacement(replace, subject, captures, result);
|
||||
previous = captures[1]; // continue after match
|
||||
if (%StringIndexOf(replace, "$", 0) < 0) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
var captures = matches[i];
|
||||
result.addSpecialSlice(previous, captures[0]);
|
||||
result.add(replace);
|
||||
previous = captures[1]; // continue after match
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < length; i++) {
|
||||
var captures = matches[i];
|
||||
result.addSpecialSlice(previous, captures[0]);
|
||||
ExpandReplacement(replace, subject, captures, result);
|
||||
previous = captures[1]; // continue after match
|
||||
}
|
||||
}
|
||||
result.add(SubString(subject, previous, subject.length));
|
||||
result.addSpecialSlice(previous, subject.length);
|
||||
return result.generate();
|
||||
};
|
||||
|
||||
@ -272,15 +281,16 @@ function ExpandReplacement(string, subject, captures, builder) {
|
||||
var peek = %StringCharCodeAt(string, position);
|
||||
if (peek == 36) { // $$
|
||||
++position;
|
||||
builder.add('$');
|
||||
} else if (peek == 38) { // $& - match
|
||||
++position;
|
||||
expansion = SubString(subject, captures[0], captures[1]);
|
||||
builder.addSpecialSlice(captures[0], captures[1]);
|
||||
} else if (peek == 96) { // $` - prefix
|
||||
++position;
|
||||
expansion = SubString(subject, 0, captures[0]);
|
||||
builder.addSpecialSlice(0, captures[0]);
|
||||
} else if (peek == 39) { // $' - suffix
|
||||
++position;
|
||||
expansion = SubString(subject, captures[1], subject.length);
|
||||
builder.addSpecialSlice(captures[1], subject.length);
|
||||
} else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
|
||||
++position;
|
||||
var n = peek - 48;
|
||||
@ -301,20 +311,21 @@ function ExpandReplacement(string, subject, captures, builder) {
|
||||
}
|
||||
}
|
||||
if (0 < n && n < m) {
|
||||
expansion = CaptureString(subject, captures, n);
|
||||
if (IS_UNDEFINED(expansion)) expansion = "";
|
||||
addCaptureString(builder, captures, n);
|
||||
} else {
|
||||
// Because of the captures range check in the parsing of two
|
||||
// digit capture references, we can only enter here when a
|
||||
// single digit capture reference is outside the range of
|
||||
// captures.
|
||||
builder.add('$');
|
||||
--position;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.add('$');
|
||||
}
|
||||
|
||||
// Append the $ expansion and go the the next $ in the string.
|
||||
builder.add(expansion);
|
||||
// Go the the next $ in the string.
|
||||
next = %StringIndexOf(string, '$', position);
|
||||
|
||||
// Return if there are no more $ characters in the string. If we
|
||||
@ -345,6 +356,19 @@ function CaptureString(string, captures, index) {
|
||||
};
|
||||
|
||||
|
||||
// Add the string of a given PCRE capture to the ReplaceResultBuilder
|
||||
function addCaptureString(builder, captures, index) {
|
||||
// Scale the index.
|
||||
var scaled = index << 1;
|
||||
// Compute start and end.
|
||||
var start = captures[scaled];
|
||||
var end = captures[scaled + 1];
|
||||
// If either start or end is missing return.
|
||||
if (start < 0 || end < 0) return;
|
||||
builder.addSpecialSlice(start, end);
|
||||
};
|
||||
|
||||
|
||||
// Helper function for replacing regular expressions with the result of a
|
||||
// function application in String.prototype.replace. The function application
|
||||
// must be interleaved with the regexp matching (contrary to ECMA-262
|
||||
|
Loading…
Reference in New Issue
Block a user