[Solved] JavaScript : Find (and Replace) text that is NOT in a specific HTML element?


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?