如果开头标签已指定类,则Javascript RegExp将替换两个标签之间的文本

时间:2019-02-19 14:47:15

标签: javascript jquery regex regexp-replace

我有以下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>

我要替换span标记之间的文本,但前提是该span标记具有“ search-text ”类。因此,就我而言,我有一个包含两个跨度的HTML代码的字符串。我要替换第二个跨度中的文本,如果其中包含搜索到的文本。

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

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

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

_paint函数:

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

这时的结果是第二个跨度完全包裹在'<span class="highlight-text">' + $0 + '</span>';中。结果是:

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

有什么想法吗?谢谢。

2 个答案:

答案 0 :(得分:1)

正则表达式是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批发的内容。)

例如,尝试在包含<span>元素的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();

答案 1 :(得分:-1)

由丹尼尔·贝克(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个),它阻止了浏览器。所以这很慢。我发布它的想法是,也许有人会分享更快的解决方案。