Javascript 如果开始标签指定 class,则 RegExp 替换两个标签之间的文本
Javascript RegExp replace text between two tags if the opening tag has specified class
我有以下 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 标签具有 class“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);
其中“value”是:“aa”和“item.html" 是我问题开头的 HTML。
_paint 函数:
_paint: function([=15=]) {
return '<span class="highlight-text">' + [=15=] + '</span>';
},
此时的结果是第二个跨度完全包含在 '<span class="highlight-text">' + [=19=] + '</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>
有什么想法吗?谢谢。
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
的内容。)
例如,尝试在包含 <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();
受 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 个)它会阻止浏览器。所以这很慢。我发布它的想法是也许有人会分享一个更快的解决方案。
我有以下 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 标签具有 class“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);
其中“value”是:“aa”和“item.html" 是我问题开头的 HTML。
_paint 函数:
_paint: function([=15=]) {
return '<span class="highlight-text">' + [=15=] + '</span>';
},
此时的结果是第二个跨度完全包含在 '<span class="highlight-text">' + [=19=] + '</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>
有什么想法吗?谢谢。
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
的内容。)
例如,尝试在包含 <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();
受 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 个)它会阻止浏览器。所以这很慢。我发布它的想法是也许有人会分享一个更快的解决方案。