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 mark
s:
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');