JS RegExp查找不在标签中的单词并替换字符串

时间:2017-10-18 17:50:09

标签: javascript regex

我需要编写第二个RegExp来查找d内不在标签中的变量sentence。因此应跳过标签中的变量。

正则表达式'(?:^|\\b)('+d+')(?=\\b|$)'会找到d变量但我需要用<span>排除class="description"标记。 新句子包含在新标签中。

sentence = "This is some word. <span class='description'>word</span> in tag should be skipped"
d = 'word'
re = new RegExp('(?:^|\\b)('+d+')(?=\\b|$)', 'gi')
sentence = sentence.replace(re, "<span>$1</span>")

我想要实现的结果是:

"This is some <span>word</span>. <span class='description'>word</span> in tag should be skipped"

我正在使用coffeescript,感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

试试这个:(word)(?![^<>]*<\/)

完整代码:

var sentence = "This is some word. <span class='description'>word</span> in tag should be skipped"
var d = 'word'
var re = new RegExp('('+d+')(?![^<>]*<\/)', 'gi')
sentence = sentence.replace(re, "<span>$1</span>")

我的回答基于以下代码段:https://regex101.com/library/gN4vI6

答案 1 :(得分:0)

尝试使用正则表达式操作HTML并不是一个好主意:迟早会遇到失败的边界条件。也许某些<>出现在属性值内部,甚至出现在文本节点内,而搜索到的术语也可能出现在意外的位置,例如HTML注释,属性值或脚本标记,......边界案例列表很长。

此外,您的搜索字词可能包含在正则表达式语法中具有特殊含义的字符,因此您至少应该逃避这些字符。

这是一个解决方案,使用DOM功能将字符串解释为HTML,并且只替换文本节点中的文本:

function escapeRegExp(str) {
    return str.replace(/[\[\]\/{}()*+?.\\^$|-]/g, "\\$&");
}

function wrapText(sentence, word) {        
    const re = new RegExp("\\b(" + escapeRegExp(word) + ")\\b", "gi"),
        span = document.createElement('span');
    span.innerHTML = sentence;
    Array.from(span.childNodes, function (node) {
        if (node.nodeType !== 3) return;
        node.nodeValue.split(re).forEach(function (part, i) {
            let add;
            if (i%2) {
                add = document.createElement('span');
                add.textContent = part;
                add.className = 'someClass';
            } else {
                add = document.createTextNode(part);
            }
            span.insertBefore(add, node);
        });
        span.removeChild(node);
    });
    return span.innerHTML;
}

const html = 'This is some word. <span class="word">word</span> should stay',
    result = wrapText(html, 'word');

console.log(result);

递归元素

在评论中,您提到您现在还希望在某些标记内进行替换,例如p

我假设您希望所有元素都发生这种情况,除了具有特定类别的元素,例如您用于包装span元素的类,但您当然可以根据需要自定义条件(例如仅递归到p或...)。

代码只需要进行一些修改:

function escapeRegExp(str) {
    return str.replace(/[\[\]\/{}()*+?.\\^$|-]/g, "\\$&");
}

function wrapText(sentence, word) {        
    const re = new RegExp("\\b(" + escapeRegExp(word) + ")\\b", "gi"),
        doc = document.createElement('span');
    doc.innerHTML = sentence;
    
    (function recurse(elem) {
        Array.from(elem.childNodes, function (node) {
            // Customise this condition as needed:
            if (node.classList && !node.classList.contains('someClass')) recurse(node);
            if (node.nodeType !== 3) return;
            node.nodeValue.split(re).forEach(function (part, i) {
                let add;
                if (i%2) {
                    add = document.createElement('span');
                    add.textContent = part;
                    add.className = 'someClass';
                } else {
                    add = document.createTextNode(part);
                }
                elem.insertBefore(add, node);
            });
            elem.removeChild(node);
        });
    })(doc);        
    return doc.innerHTML;
}
const html = '<p><b>Some word</b></p>. <span class="someClass">word</span> should stay',
    result = wrapText(html, 'word');
console.log(result);