Home > OS >  Replace words except the ones inside braces
Replace words except the ones inside braces

Time:09-21

I have a markdown string like this Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.
I want to wrap searched words (see the function below) with <mark></mark>, but skip the link (url.com/apps/list?appid=q1w2e3) so I will have TODO <mark>app</mark> but not url.com/<mark>app</mark>s/list?<mark>app</mark>id=q1w2e3

How can I achieve that?

The code I'm using to add marks:

const garbage = /[|\\{}()[\]^$ *?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim();
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(garbage, '').split(' ');

  const result = wordsToFind.reduce((result, word) => {
    const re = new RegExp(`(${word})`, 'gi');

    return result.replace(re, (word) => `<mark>${word}</mark>`);
  }, originalString);

  return result;
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

UPD I'm trying to mark not only app but also <mark>app</mark>s, because this function is for user's search

CodePudding user response:

It may be enough to ensure that the word is not preceded/followed by alpha numericals, nor some specific characters like /, &, = and -.

Also, you can do this with one regex, and don't need a callback as argument for the replace call. You can use a back-reference $&:

const garbage = /[|\\{}()[\]^$ *?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim().replace(garbage, '');
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(/ /g, '|');
  const re = new RegExp(`(?<![/=&-])\\b(${wordsToFind})\\b(?![/=&-])`, 'gi');
  return originalString.replace(re, '<mark>$&</mark>');
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

CodePudding user response:

You could remove the flag g but it will just change the first app matched not the one inside brackets [TODO app], to do So you can define a variable times and define how many times you want the word app be replaced!

const garbage = /[|\\{}()[\]^$ *?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim();
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(garbage, '').split(' ');
  let times = 0; // Define here
  const result = wordsToFind.reduce((result, word) => {
    const re = new RegExp(`(${word})`, 'gi');

    return result.replace(re, (word) => {
        if(times<2){
            times  ; // increment here
            return `<mark>${word}</mark>`;
        }
        return word;
        
    });
  }, originalString);

  return result;
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

CodePudding user response:

Better Solution use word boundary \b

const re = new RegExp(`\\b(${word})\\b`, 'gi');
  • Related