首页 > 解决方案 > Javascript中的整个单词正则表达式匹配和超链接

问题描述

我需要一些关于正则表达式的帮助。

我正在使用 Javascript 和 JQuery 来超链接 HTML 文档中的术语,为此我使用以下代码。我正在为大量文档中的多个术语执行此操作。

var searchterm = "Water";

jQuery('#content p').each(function() {

  var content = jQuery(this),
      txt = content.html(),
      found = content.find(searchterm).length,
      regex = new RegExp('(' + searchterm + ')(?![^(<a.*?>).]*?<\/a>)','gi');

  if (found != -1) {
    //hyperlink the search term
    txt = txt.replace(regex, '<a href="/somelink">$1</a>');
    content.html(txt);
  }
});

然而,有一些我不想匹配的实例,由于时间限制和大脑融化,我正在寻求一些帮助。


编辑:我已经根据@ggorlen 提供的优秀示例更新了下面的代码笔,谢谢!

示例 https://codepen.io/julian-young/pen/KKwyZMr

标签: javascriptjqueryregex

解决方案


将整个 DOM 转储为原始文本并使用正则表达式对其进行解析绕过了 jQuery(以及扩展为 JS)的主要目的,即将 DOM 作为节点的抽象树进行遍历和操作。

文本节点有一个,我们可以在遍历中使用它来识别您感兴趣的非链接节点。nodeType Node.TEXT_NODE

获得文本节点后,可以适当地应用正则表达式(解析文本,而不是 HTML)。我用于<mark>演示目的,但您可以将其设为锚标记或任何您需要的标记。

jQuery 为您提供了replaceWith一种在您进行所需的正则表达式替换后替换节点内容的方法。

$('#content li').contents().each(function () {
  if (this.nodeType === Node.TEXT_NODE) {    
    var pattern = /(\b[Ww]aters?(?!-)\b)/g;
    var replacement = '<mark>$1</mark>';
    $(this).replaceWith(this.nodeValue.replace(pattern, replacement));
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Example Content</h1>
<div id="content">
  <ul>
    <li>Water is a fascinating subject. - <strong>match</strong></li>
    <li>We all love water. - <strong>match</strong></li>
    <li>ice; water; steam - <strong>match</strong></li>
    <li>The beautiful waters of the world - <strong>match</strong> (including the s)</li>
    <li>and all other water-related subjects - <strong>no match</strong></li>
    <li>and this watery topic of - <strong>no match</strong></li>
    <li>of WaterStewardship looks at how best - <strong>no match</strong></li>
    <li>On the topic of <a href="/governance">water governance</a> - <strong>no match</strong></li>
    <li>and other <a href="/water">water</a> related things - <strong>no match</strong></li>
    <li>the best of <a href="/allthingswater">all things water</a> - <strong>no match</strong></li>
  </ul>
</div>

您可以在没有 jQ 的情况下执行此操作并应用于文档中的所有内容:

for (const parent of document.querySelectorAll("body *:not(a)")) {
  for (const child of parent.childNodes) {
    if (child.nodeType === Node.TEXT_NODE) {
      const pattern = /(\b[Ww]aters?(?!-)\b)/g;
      const replacement = "<mark>$1</mark>";
      const subNode = document.createElement("span");
      subNode.innerHTML = child.textContent.replace(pattern, replacement);
      parent.insertBefore(subNode, child);
      parent.removeChild(child);
    }    
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  hello water
  <div>
    <div>
      I love Water.
      <a href="">more water</a>
    </div>
    watership down
    <h4>watery water</h4>
    <p>
      waters
    </p>
    foobar <a href="">water</a> water
  </div>
</div>


推荐阅读