【问题标题】:Javascript RegExp replace text between two tags if the opening tag has specified class如果开始标签已指定类,则 Javascript RegExp 替换两个标签之间的文本
【发布时间】:2019-07-13 02:44:45
【问题描述】:

我有以下 HTML 代码:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span>

我想替换跨度标记之间的文本,但前提是跨度标记具有类“search-text”。所以在我的例子中,我有一个包含两个跨度的 HTML 代码的字符串。如果第二个跨度包含搜索到的文本,我想替换它。

我搜索:“aa”,我想用&lt;span class="highlight-text"&gt;aa&lt;/span&gt; 替换它。所以最终的结果应该是:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-search">AA</span>A</span>

现在我正在做类似的事情:

var paint = $.proxy(this._paint, this);
var regex = /(<span class="search-text[^>]+>|<\/span>)/g;
item.node.innerHTML = item.html.replace(regex, paint);

其中“value”是:“aa”和“item.html”是我的问题开头显示的 HTML。

_paint 函数:

_paint: function($0) {
   return '<span class="highlight-text">' + $0 + '</span>';
},

此时结果是第二个跨度完全包裹在 '&lt;span class="highlight-text"&gt;' + $0 + '&lt;/span&gt;'; 中。结果如下:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="highlight-text"><span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span></span>

我只想将文本匹配包含在 hghlight 范围内,如下所示:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-text">AA</span>A</span>

有什么想法吗?谢谢。

【问题讨论】:

  • 最好的办法是创建一个文档片段,将 HTML 文本放入其中,然后使用普通的 DOM API 来查找和操作 HTML。使用正则表达式处理 HTML 是一团糟。
  • 如果这是已经页面代码,那么您可能甚至不需要文档片段。否则,如果你有一个 HTML 字符串,那么你可以这样做。正则表达式会。如果search-textsecond 类怎么办?还是第三?如果class 属性甚至不是元素中的第一个属性怎么办?
  • 我不是在操作 DOM,我已经有一个包含所有项目的数组。该数组包含项目文本和项目 html。
  • 将它们转换为文档片段并在其上使用 DOM 工具可能仍然比尝试针对 HTML 允许的许多可能变化进行正则表达式更容易。但是,如果您显示该数组,以便我们可以看到您实际使用的是什么,您可能会得到更好的答案

标签: javascript jquery regex regexp-replace


【解决方案1】:

Regex 是 notoriously 大部分工作的错误工具;它是为处理字符串而设计的,而不是用于处理 HTML 等结构化数据。幸运的是,您已经在浏览器中,因此您拥有一整套专为 DOM 操作而设计的工具集:不妨使用它。 (您还使用 jQuery 标记了问题,这使得问题变得更加容易。)

更新:我误读了问题中的一个细节,并且从父节点的属性中而不是从外部提取搜索字符串;我也未能使搜索不区分大小写。两者现在都在下面更正了:

// Make a case-insensitive regex from the search string
let str = 'aa';
let re = new RegExp(str, "gi");

// operate only on the .search-text nodes:
$('.search-text').each(function(i, el) {
  // get the current contents of the element:
  let text = $(el).html();

  // Add your highlights:
  text = text.replace(re, '<span class="highlight-text">$&</span>');

  // insert the modified text back into the DOM:
  $(el).html(text);
})
.highlight-text {
  background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span> I

这只有在.search-text 元素没有子节点时才真正安全。 通常即使它们包含一些 HTML,它也会工作,但前提是:

  • 您确定要突出显示的字符串永远不会匹配 HTML 本身的某些部分,并且
  • 没有任何事件绑定附加到 DOM 元素(此脚本替换了 .search-text 批发的内容。)

例如,尝试在包含 &lt;span&gt; 元素的 html 字符串中突出显示单词“span”会导致 html 无效:

// same script as above
$('.search-text').each(function(i, el) {
  let text = $(el).html();
  let highlights = $(el).attr("attribute").split(" ");
  for (str of highlights) {
    text = text.replace(str, '<span class="highlight-text">' + str + '</span>');
  }
  $(el).html(text);
})
.highlight-text {
  background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span class="search-text" attribute="span">Text AAA <span>test</span></span>

以字符串开头

如果您的起点是一个 HTML 字符串而不是一个已经构建的 DOM 树,那么您需要做的就是先将该字符串转换为一个文档片段,以便您可以在其上使用这些 DOM 工具:

let fragment = $('<template>');
fragment.html($yourStringHere);
/* manipulate fragment contents as above, then */
return fragment.html();

【讨论】:

  • 你可以使用一个变量,例如:$string = "AAA BBB Text AAA I";并处理此变量以替换文本而不是处理 DOM?在我的示例中,我有一个包含 HTML 的字符串,我想用一个新字符串替换它。
  • 当然,我在答案中添加了这个。
【解决方案2】:

受 Daniel Beck 回答启发的部分解决方案。此解决方案不操纵 DOM。 (我只是将结果显示在 DOM 上以进行演示)

https://jsfiddle.net/mt2yz90L/3/

HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result">
</div>

JS:

  let searchedText = 'aa';
  let html ='<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span><span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span> I';
  var htmlParts = html.split(/(<span class="search-text[^>]+>|<\/span>)/g);
  var htmlPartsIndex = 0;
  for(var i=0; i < htmlParts.length; i++) {
    if(htmlParts[i].indexOf('search-text') !== -1) {
        htmlPartsIndex = ++i;
      break;
    }
  }
  if(htmlPartsIndex > 0) {
     htmlParts[htmlPartsIndex] = htmlParts[htmlPartsIndex].toLowerCase().replace(searchedText, '<span class="highlight-text">' + searchedText + '</span>')
  }
  $('#result').html(htmlParts.join(''));

CSS:

.highlight-text {
  background-color: red;
}

我唯一的问题是,在我的情况下(超过 300 个要解析的项目)它会阻止浏览器。所以这很慢。我发布它的想法是也许有人会分享一个更快的解决方案。

【讨论】:

    猜你喜欢
    • 2016-05-24
    • 2016-02-12
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多