まず、以前に行った置換を最終的に上書きしないようにするために、逆方向に反復する必要がありますが、私の例では、文字列が最後に一度に再構築されるため、重要ではありません。
// > interpolateOnIndices([[5,9], [23,27]], "eggs eggs spam and ham spam");
// < 'eggs <span>eggs</span> spam and ham <span>spam</span>'
function interpolateOnIndices(indices, string) {
"use strict";
var i, pair, position = string.length,
len = indices.length - 1, buffer = [];
for (i = len; i >= 0; i -= 1) {
pair = indices[i];
buffer.unshift("<span>",
string.substring(pair[0], pair[1]),
"</span>",
string.substring(pair[1], position));
position = pair[0];
}
buffer.unshift(string.substr(0, position));
return buffer.join("");
}
splice
これは、追加の配列を作成しないため、ingを使用した例よりも少し優れています(スプライス自体が追加の配列を作成します)。マッピングを使用して関数を他の関数内で繰り返し作成することは、特定のメモリを大量に消費しますが、あまり高速ではありません...ただし、少し短くなります。
大きな文字列では、理論的には、結合すると、複数の連結よりも有利になります。これは、メモリの割り当てが、後で中途半端な文字列を破棄するのではなく、一度だけ行われるためです。もちろん、大量のデータを処理しているのでない限り、これらすべてを気にする必要はありません。
編集:
手に余る時間があったので、テストを行うことにしました。より大きな(しかしかなり現実的な)データセットでバリエーションがどのように比較されるかを確認するために、以下にいくつかの結果を含むテストコードを示します...
function interpolateOnIndices(indices, string) {
"use strict";
var i, pair, position = string.length,
len = indices.length - 1, buffer = [];
for (i = len; i >= 0; i -= 1) {
pair = indices[i];
buffer.unshift("<span>",
string.substring(pair[0], pair[1]),
"</span>",
string.substring(pair[1], position));
position = pair[0];
}
buffer.unshift(string.substr(0, position));
return buffer.join("");
}
function indexWrap(indexArr, str) {
var chars = str.split("");
for(var i = 0; i < indexArr.length; i++) {
var indexes = indexArr[i];
if(chars[indexes[0]] && chars[indexes[1]]){
chars.splice(indexes[0], 0, "<span>");
chars.splice(indexes[1], 0, "</span>");
}
}
return chars.join("");
}
function replaceOffset(str, offs, tag) {
tag = tag || "span";
offs.reverse().forEach(
function(v) {
str = str.replace(
new RegExp("(.{" + v[0] + "})(.{" + (v[1] - v[0]) + "})"),
"$1<" + tag + ">$2</" + tag + ">"
);
});
return str;
}
function generateLongString(pattern, times) {
"use strict";
var buffer = new Array(times);
while (times >= 0) {
buffer[times] = pattern;
times -= 1;
}
return buffer.join("");
}
function generateIndices(pattern, times, step) {
"use strict";
var buffer = pattern.concat(), block = pattern.concat();
while (times >= 0) {
block = block.concat();
block[0] += step;
block[1] += step;
buffer = buffer.concat(block);
times -= 1;
}
return buffer;
}
var longString = generateLongString("eggs eggs spam and ham spam", 100);
var indices = generateIndices([[5,9], [23,27]], 100,
"eggs eggs spam and ham spam".length);
function speedTest(thunk, times) {
"use strict";
var start = new Date();
while (times >= 0) {
thunk();
times -= 1;
}
return new Date() - start;
}
speedTest(
function() {
replaceOffset(longString, indices, "span"); },
100); // 1926
speedTest(
function() {
indexWrap(indices, longString); },
100); // 559
speedTest(
function() {
interpolateOnIndices(indices, longString); },
100); // 16
amd64 Linux(FC-17)でV8(Node.js)に対してテストされています。
そのライブラリをロードしたくなかったので、undefinedの答えをテストしませんでした。特に、このテストに役立つことは何もしません。私はそれがandbeyondとelclanrsの変種の間のどこかで、しかしelclanrsの答えにもっと役立つだろうと想像します。