【问题标题】:Multiple look-arounds and ignore inside tags多个环顾四周并忽略内部标签
【发布时间】:2019-09-24 20:31:27
【问题描述】:

我想查找不属于另一个单词的文本(让这个工作),但我也想查找位于 <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");

【问题讨论】:

  • 谨慎使用正则表达式来解析 HTML。我去过那里 - 当你有嵌套元素时,它本身是不够的。
  • 是的,不幸的是我无法避免它,我有一个添加链接的正则表达式,但如果它在 标记内再次找到该单词,它会加倍
  • 明白了。我可能有办法解决这个问题……但我不确定你的 HTML 到底是什么样子。例如,我在这里看到了一个不合适的 &lt;li&gt; 标签。这可能会改变 DOM 实际变成的样子。
  • 抱歉忽略
  • 只是在测试一些东西

标签: javascript regex regex-lookarounds


【解决方案1】:

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

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

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

Regex Demo

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

我注意到您在原始正则表达式中使用了 negative lookbehind - 这实际上在 2018 年之前的 JavaScript 中不支持,因此您可能需要注意这一点。 Lookbehinds 仅在 browsers supporting ECMA2018 standard 中可用。

如果你想解决这个问题而不需要消极的回顾,你可以尝试:

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

Regex Demo

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

【讨论】:

    【解决方案2】:

    解决此问题的一种方法是在&lt;a&gt; 标签上拆分字符串,然后独立处理字符串的每个部分,仅当部分不以&lt;a 开头时,将Java 替换为++JavaUpdated++

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

    【讨论】:

      【解决方案3】:

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

      // 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++')
      })
      &lt;div class="js-text"&gt;Java Javascript &lt;a href=""&gt;Some Java here&lt;/a&gt; more java&lt;/div&gt;

      【讨论】:

        猜你喜欢
        相关资源
        最近更新 更多
        热门标签