Home > Back-end >  Find once and return different strings replaced with different words
Find once and return different strings replaced with different words

Time:10-08

const str = 'i love code. i write code everyday.'
const regex = /code/g

const outputJs   = str.replace(regex, 'js'  )
const outputCss  = str.replace(regex, 'css' )
const outputHtml = str.replace(regex, 'html')

Here I am searching for /code/g three times and replacing with different strings.

Is there any way to optimize this code?

Because if the regex gets complicated and the str is very long then the javascript engine will take some time to search for the same thing again and again just to replace with a different word.

I hope you understand what I'm trying to do.

EDIT: A workaround would be:

  1. Generate a set of template strings using the regex.exec(str) and some string manipulation.
  2. Use those template strings to generate output by concatenating replacement strings in-between them.

CodePudding user response:

You can use a split, and work on the array to do the replace:

const str = 'i love code. i write code everyday.';
let outputJs;
let outputCss;
let outputHtml;
let startTime = new Date();
for(let i = 0; i < 1000000; i  ) {
  outputJs = [];
  outputCss = [];
  outputHtml = [];
  str.split(/\b(code)\b/).forEach(item => {
    if(item === 'code') {
      outputJs.push('js');
      outputCss.push('css');
      outputHtml.push('html');
    } else {
      outputJs.push(item);
      outputCss.push(item);
      outputHtml.push(item);
    }
  });
}
console.log('outputJs:   '   outputJs.join(''));
console.log('outputCss:  '   outputCss.join(''));
console.log('outputHtml: '   outputHtml.join(''));
console.log('time: '   (new Date() - startTime)   ' ms');
Output:

outputJs:   i love js. i write js everyday.
outputCss:  i love css. i write css everyday.
outputHtml: i love html. i write html everyday.
time: 386 ms

In my test 1,000,000 runs took 386 ms.

Now let's compare that to distinct replaces:

const str = 'i love code. i write code everyday.';
let outputJs;
let outputCss;
let outputHtml;
let startTime = new Date();
for(let i = 0; i < 1000000; i  ) {
  outputJs = str.replace(/\b(code)\b/g, 'js');
  outputCss = str.replace(/\b(code)\b/g, 'css');
  outputHtml = str.replace(/\b(code)\b/g, 'html');
}
console.log('outputJs:   '   outputJs);
console.log('outputCss:  '   outputCss);
console.log('outputHtml: '   outputHtml);
console.log('time: '   (new Date() - startTime)   ' ms');
Output:

outputJs:   i love js. i write js everyday.
outputCss:  i love css. i write css everyday.
outputHtml: i love html. i write html everyday.
time: 494 ms

In my test 1,000,000 runs took 494 ms. As you can see this is slightly slower, e.g. the split method is not worth the added complexity.

CodePudding user response:

Here's a fairer benchmark:

  • Baseline

    const str = 'i love code. i write code everyday.';
    let outputJs;
    let outputCss;
    let outputHtml;
    const startTime = Date.now();
    for (let i = 0; i < 1000000; i  ) {
      outputJs = str.replace(/\bcode\b/g, 'js');
      outputCss = str.replace(/\bcode\b/g, 'css');
      outputHtml = str.replace(/\bcode\b/g, 'html');
    }
    const endTime = Date.now();
    console.log('outputJs:   '   outputJs);
    console.log('outputCss:  '   outputCss);
    console.log('outputHtml: '   outputHtml);
    console.log(`time: ${endTime - startTime} ms`);
    
      

  • split once, join thrice:

    const str = 'i love code. i write code everyday.';
    let outputJs;
    let outputCss;
    let outputHtml;
    const startTime = Date.now();
    for (let i = 0; i < 1000000; i  ) {
      const parts = str.split(/\bcode\b/g);
      outputJs = parts.join('js');
      outputCss = parts.join('css');
      outputHtml = parts.join('html');
    }
    const endTime = Date.now();
    console.log('outputJs:   '   outputJs);
    console.log('outputCss:  '   outputCss);
    console.log('outputHtml: '   outputHtml);
    console.log(`time: ${endTime - startTime} ms`);
    
      

  • split once, use forEach to replace, join by empty string (from @PeterThoeny's answer)

    const str = 'i love code. i write code everyday.';
    let outputJs;
    let outputCss;
    let outputHtml;
    const startTime = Date.now();
    for (let i = 0; i < 1000000; i  ) {
      const jsParts = [];
      const cssParts = [];
      const htmlParts = [];
      str.split(/\b(code)\b/).forEach(item => {
        if(item === 'code') {
          jsParts.push('js');
          cssParts.push('css');
          htmlParts.push('html');
        } else {
          jsParts.push(item);
          cssParts.push(item);
          htmlParts.push(item);
        }
      });
      outputJs = jsParts.join('');
      outputCss = cssParts.join('');
      outputHtml = htmlParts.join('');
    }
    const endTime = Date.now();
    console.log('outputJs:   '   outputJs);
    console.log('outputCss:  '   outputCss);
    console.log('outputHtml: '   outputHtml);
    console.log(`time: ${endTime - startTime} ms`);
    
      

Actually the original, simple code is the fastest. Regex engines are well-optimised.

  • Related