Match and Substitute

JavaScript performance comparison

Revision 4 of this test case created by nhahtdh

Info

This test compares some ways of substituting parts of a string with new parts provided. In principle, the process should return a string which has any parenthesised digits in it replaced by values taken from the appropriate place in the array.

So given an array consisting of just the words "is" and "test", the result for "this (0) a (1) sentence" should be "this is a test sentence". If anything goes wrong, the result should just return the original or a partially-transformed string.

See an old school match-and-substitute process in action here: http://jsfiddle.net/guypursey/82APF/

[I added a more concise version which is not JSLint-approved but does make the code more concise. I wanted to see if the more concise code was also more efficient.]

See a newer lambda-replace process for the same result here: http://jsfiddle.net/guypursey/8bL8a/

Preparation code

<div id="result"></div>
<script>
Benchmark.prototype.setup = function() {
    var rgM = /\((\d+)\)/,
        rgR = /\((\d+)\)/g,
        str = "This (0) a (1) sentence. This sentence (0) a (1). The result should (2) a sentence (3) any numbers (4) it. Let's (5) what the result actually (0). Crucially, let's (5) if an old style while-loop (0) faster than an anonymous function inside a String.replace() call (3) all those extraneous variables getting (5) the way. This (0) the real (1) of the sentence!",
        sub = [
                "is",
                "test",
                "be",
                "without",
                "in",
                "see"
            ],
        result;
};

Benchmark.prototype.teardown = function() {
    document.getElementById('result').innerHTML = result;
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Match and substitute while-loop
var mch = rgM.exec(str),
    parsed,
    remainder;
if (mch) {
    parsed = '';
    remainder = str;
    while (mch) {
        parsed += remainder.substring(0, mch.index) + sub[mch[1]];
        remainder = remainder.substring(mch.index + mch[0].length);
        mch = rgM.exec(remainder);
    }
    result = parsed + remainder;
} else {
    result = str;
}
pending…
Match and substitute while-loop with assignment in place of conditional (not JSLint-valid)
var mch,
    parsed = '',
    remainder = str;
while (mch = rgM.exec(remainder)) {
    parsed += remainder.substring(0, mch.index) + sub[mch[1]];
    remainder = remainder.substring(mch.index + mch[0].length);
}
result = (parsed) ? parsed + remainder : str;
pending…
Lambda-replace
result = str.replace(rgR, function() {
    return sub[arguments[1]];
});
pending…
exec with global regex
var mch,
    parsed = '',
    lastAppend = 0;

    while ((mch = rgR.exec(str)) !== null) {
        parsed += str.substring(lastAppend, mch.index) + sub[mch[1]];
        lastAppend = mch.index + mch[0].length;
    }
    result = parsed + str.substring(lastAppend);
 
pending…
Lambda-replace 2
result = str.replace(rgR, function(_, $1) {
    return sub[$1];
});
pending…
exec with global regex 2
var mch,
    parsed = '',
    lastAppend = 0;

    while ((mch = rgR.exec(str)) !== null) {
        parsed += str.substring(lastAppend, mch.index) + sub[mch[1]];
        lastAppend = rgR.lastIndex;
    }
    result = parsed + str.substring(lastAppend);
 
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment