多次环视并忽略内部标签
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>)
本质上,我们是在检查 Java
前面或后面除了空格之外没有任何内容,然后使用否定前瞻来检查标签中的文本。
我注意到您在原始正则表达式中使用了 负向后视 - 这实际上不受 JavaScript 2018 年之前的支持,因此您可能想要请注意这一点。回顾仅在 browsers supporting ECMA2018 standard.
中可用
如果你想在没有负面回溯的情况下解决这个问题,你可以尝试:
(?:\s$|^)Java(?![^\s])(?!(.(?!<a))*<\/a>)
本质上说不匹配 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>
我想找到不属于另一个词的文本(让这个工作正常),但我也想 不 找到 <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>)
本质上,我们是在检查 Java
前面或后面除了空格之外没有任何内容,然后使用否定前瞻来检查标签中的文本。
我注意到您在原始正则表达式中使用了 负向后视 - 这实际上不受 JavaScript 2018 年之前的支持,因此您可能想要请注意这一点。回顾仅在 browsers supporting ECMA2018 standard.
中可用如果你想在没有负面回溯的情况下解决这个问题,你可以尝试:
(?:\s$|^)Java(?![^\s])(?!(.(?!<a))*<\/a>)
本质上说不匹配 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>