【问题标题】:JS RegExp finding word that is not in tag and replace string [duplicate]JS RegExp查找不在标签中的单词并替换字符串[重复]
【发布时间】:2017-10-18 17:50:09
【问题描述】:

我需要编写第二个 RegExp 以在 sentence 内找到不在标签中的变量 d。所以标签中的变量应该被跳过。

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

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,感谢您的帮助。

【问题讨论】:

  • 您的字符串文字无效。并且RegExpt 应该没有t(除非你有一个同名的函数)
  • @trincot 谢谢,我是 RegExp 的新手,你能帮忙用这个例子吗?
  • 请花点时间阅读this masterpiece
  • @DineiRockenbach 有没有其他方法可以在字符串中查找单词(后跟逗号、点等(某些规则))并将其包装在新标签中?谢谢
  • @user7754069 您的字符串是 XML/HTML 摘录还是带有一些标签的随机字符串?

标签: javascript regex


【解决方案1】:

试试这个:(word)(?![^&lt;&gt;]*&lt;\/)

完整代码:

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>")

我的这个答案基于这个 sn-p:https://regex101.com/library/gN4vI6

【讨论】:

  • 谢谢迪内!我们可以包括我的正则表达式,因为我需要通过一些规则找到一个“单词”: - 后跟符号(点、逗号等)或者它在句子的开头。 - 现在我想选择“单词”。但不是“半字”。所以结果是:word 但不是半word
  • 这也将替换&lt;span myattr="a word"&gt;hello&lt;/span&gt;中的“word”。
  • @trincot 是的,我需要“跳过”整个跨度并包含我以前的正则表达式
【解决方案2】:

尝试使用正则表达式来操作 HTML 不是一个好主意:迟早你会遇到一些边界条件,它会失败。可能一些&lt;&gt; 出现在属性值内部,甚至文本节点内部,而搜索到的词也可能出现在意想不到的地方,如HTML cmets、属性值或脚本标签中,... 边界列表案例很长。

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

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

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);

递归到元素中

在您提到的 cmets 中,您现在还希望在某些标签中进行替换,例如 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);

【讨论】:

  • 谢谢你,我稍后会尝试并给你反馈,虽然它看起来会起作用!
  • @user7754069 new RegExp("\\b(" + escapeRegExp(word) + ")\\b", "gi") 如果word 以非单词字符开头/结尾将不起作用。
  • 好吧,它会起作用,因为如果非字母数字和字母数字之间存在中断,无论方向可能是什么,它都会匹配。例如,如果单词是“-abc”,那么它不会在“---abc---”中匹配,但会在“abc-abc---”中匹配。但是在字符串的开头/结尾处,它确实是违反直觉的。
  • @trincot 再次感谢您的帮助。我有一个问题:有没有办法写出不同的“过滤器(节点=> node.nodeType === 3)”表达式,因为我无法将它转换为coffeescript,它说不支持ArrowFunctionExpression。我用js2.coffee
  • 我已将代码更新为不使用箭头函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2017-12-20
  • 1970-01-01
相关资源
最近更新 更多