Replace placeholders (v2)

Revision 2 of this benchmark created on


Setup

const replaceByMap0 = (str, replaceMap) => {
    return Object.keys(replaceMap).reduce((acc, id) => {
        return acc.replace(id, replaceMap[id]);
    }, str);
};
const chartsForEscape = /([^a-zA-Z0-9])/g;
const escapeRegExpSyntax = (str) => str.replace(chartsForEscape, '\\$1');
const replaceByMap1 = (str, replaceMap) => {
    const regexp = new RegExp(Object.keys(replaceMap)
        .map((s) => `(${escapeRegExpSyntax(s)})`)
        .join('|'), 'g');
    return str.replace(regexp, (str) => replaceMap[str] ?? str);
};
const replaceByMap1Cached = (str, replaceMap) => {
    return str.replace(regexp, (str) => replaceMap[str] ?? str);
};
const replaceByMap2 = (str, replaceMap) => {
    const indexes = Object.keys(replaceMap)
        .map((id) => {
        const start = str.indexOf(id);
        if (start === -1) {
            return undefined;
        }
        return {
            start,
            id,
            content: replaceMap[id],
        };
    })
        .filter((x) => Boolean(x))
        .sort((a, b) => a.start - b.start);
    if (!indexes.length) {
        return str;
    }
    return indexes.reduce((acc, { start, id, content }, i, arr) => {
        const next = arr[i + 1];
        const tailPart = str.substring(start + id.length, next ? next.start : undefined);
        return acc + content + tailPart;
    }, str.substring(0, indexes[0].start));
};
const replaceByMap3Cached = (str, replaceMap) => {
    return str
        .split(regexp)
        .map((s) => replaceMap[s] ?? s)
        .join('');
};
const replaceByMap3 = (str, replaceMap) => {
    const regexp = new RegExp(Object.keys(replaceMap)
        .map((s) => `(${escapeRegExpSyntax(s)})`)
        .join('|'), 'g');
    return str
        .split(regexp)
        .map((s) => replaceMap[s] ?? s)
        .join('');
};
function makeBigStr(length) {
    let result = '';
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ()/?><';
    const charactersLength = characters.length;
    let counter = 0;
    while (counter < length) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength));
        counter += 1;
    }
    return result;
}
const bigStr = makeBigStr(2 * (1 << 20));
const getRandomSubstr = (length, str) => {
    const start = Math.floor(Math.random() * str.length - length);
    return str.substring(start, start + length);
};
const replaceMap = Object.fromEntries([
    [getRandomSubstr(20, bigStr), makeBigStr(5 * (1 << 10))],
    [getRandomSubstr(20, bigStr), makeBigStr(5 * (1 << 10))],
    [getRandomSubstr(10, bigStr), makeBigStr(4 * (1 << 20))],
    [getRandomSubstr(20, bigStr), makeBigStr(5 * (1 << 10))],
]);
const regexp = new RegExp(Object.keys(replaceMap)
        .map((s) => `(${escapeRegExpSyntax(s)})`)
        .join('|'), 'g');

Test runner

Ready to run.

Testing in
TestOps/sec
multiply replace
replaceByMap0(bigStr, replaceMap)
ready
replace(regexp, () => {})
replaceByMap1(bigStr, replaceMap)
ready
multiply indexOf + reduce + substring
replaceByMap2(bigStr, replaceMap)
ready
split + join
replaceByMap3(bigStr, replaceMap)
ready
replace(regexp, () => {}) with RegExp cache
replaceByMap1Cached(bigStr, replaceMap)
ready
split + join with RegExp cache
replaceByMap3Cached(bigStr, replaceMap)
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.