If, and only if, there are no nested <span>
-tags, you can search for
/(<span\b[^>]*>[\s\S]*?<\/span>)|(\b(?:foo|bar)(?:\s+(?:foo|bar))*)/g
and replace it with the function
function matchEvaluator(_, span, word) {
if (span) return span;
return '<span class="widget">' + word + '</span>';
}
- the part
(<span\b[^>]*>[\s\S]*?<\/span>)
searches for the span element.
That’s the part, where no nested<span>
-element is allowed. The matched text is returnd unchanged (the reason to match them is to consume all the characters inside<span>
) <span\b[^>]*>
searches for the start tag – this could be not sufficient for your needs. Maybe you’ll try to be more specific, e.g. something like<span\b(?:\s+\w[\w-]*(?:=(?:"[^"]*"|'[^']*'|\S*)))*>
(\b(?:foo|bar)(?:\s+(?:foo|bar))*)
searches for the words “foo” and “bar”
If there is one, it searches for space characters and another “foo”
or “bar” (repeatedly).
Since the<span>
-tags and all their content is already consumed, you can only match “foo” and “bar” outside<span>
- the matchEvaluator-function tests, if a span element is matched and if so, simply returns the matched text. Otherwise, the words are matched and they are returned wrapped into the new span..
Test:
var texts = [
"This is a foo bar sentence",
"This sentence contains a <span class="widget">foo bar</span> value"
];
var wordsOutsideSpan_rx = /(<span\b[^>]*>[\s\S]*?<\/span>)|(\b(?:foo|bar)(?:\s+(?:foo|bar))*)/g;
function wrapInSpan(_, span, word) {
if (span) return span;
return '<span class="widget">' + word + '</span>';
}
texts.forEach(function (txt) {
console.log(txt.replace(wordsOutsideSpan_rx, wrapInSpan));
});
// outputs
// "This is a <span class="widget">foo bar</span> sentence"
// "This sentence contains a <span class="widget">foo bar</span> value"
5
solved JavaScript : Find (and Replace) text that is NOT in a specific HTML element?