多次环视并忽略内部标签

Multiple look-arounds and ignore inside tags

我想找到不属于另一个词的文本(让这个工作正常),但我也想 找到 <a> 中的文本标签

"Java <li>Javascript</li> <a href="">Some Java here</a> more java"

var regex2 = new RegExp(`(?<![a-z])Java(?![a-z])`, "gi");

text = text.replace(regex2, '++JavaUpdated++');

上面的工作但下面的额外环顾四周不

var regex2 = new RegExp(`(?<![a-z])(?<!<a.*)Java(?!.*<\/a>)(?![a-z])`, "gi");

解决此问题的一种方法是在 <a> 标记上拆分字符串,然后独立处理字符串的每个部分,仅当该部分不存在时才将 Java 替换为 ++JavaUpdated++ '以 <a:

开头

const str = 'Java <li>Javascript</li> <a href="">Some Java here</a> more java';

let newstr = str.split(/(<a.*?<\/a>)/)
                .map(v => (v.slice(0, 2) == '<a') ? v : v.replace(/\bJava\b/i, '++JavaUpdated++'))
                .join();

console.log(newstr);

Don't parse HTML with regex,但如果你坚持...

如果您使用的浏览器允许后视(见下文),则可以使用以下正则表达式:

(?<![^\s])Java(?![^\s])(?!(.(?!<a))*<\/a>)

Regex Demo

本质上,我们是在检查 Java 前面或后面除了空格之外没有任何内容,然后使用否定前瞻来检查标签中的文本。

我注意到您在原始正则表达式中使用了 负向后视 - 这实际上不受 JavaScript 2018 年之前的支持,因此您可能想要请注意这一点。回顾仅在 browsers supporting ECMA2018 standard.

中可用

如果你想在没有负面回溯的情况下解决这个问题,你可以尝试:

(?:\s$|^)Java(?![^\s])(?!(.(?!<a))*<\/a>)

Regex Demo

本质上说不匹配 Java 如果前面有除空格或行首以外的任何内容(否则,将是单词的一部分)。

假设您不需要处理文本可能在何处分成单独的文本节点,下面的代码片段应该涵盖逻辑。这个想法是只遍历 DOM 中的文本节点并忽略沿途的任何锚标记。

// Your RegExp, just as a literal
const re = /(?<![a-z])Java(?![a-z])/gi

const walkTextNodesIgnoringAnchors = (el, fn) =>
  el.childNodes.forEach(child => {
    // Ignore anchors
    if (child.nodeName === 'A') return
    
    // On Text nodes, call fn
    else if (child.nodeName === '#text') fn(child)
    
    // Otherwise, recursively walk further down
    else walkTextNodes(child, fn)
  })

const textEl = document.querySelector('.js-text')

walkTextNodesIgnoringAnchors(textEl, (textNode) => {
  textNode.textContent = textNode.textContent.replace(re, '++JavaUpdated++')
})
<div class="js-text">Java Javascript <a href="">Some Java here</a> more java</div>