JavaScript:查找(并替换)不在特定HTML元素中的文本?
TL;博士摘要 如何在当前页面的HTML中找到的特定单词或短语周围插入一个,但忽略已包含在我尝试插入的相同范围内的文本 由于要处理大量的值,这必须是高性能的 示例: 搜索“foo” 应找到匹配项: 这句话包含一个foo-bar值 如果未找到匹配项: 这句话包含一个foo-bar值 背景-即为什么? 我正在研究一个特定的问题,即必须在页面上动态找到的特定文本周围注入元素。我正在寻找的文本是一个大数组JavaScript:查找(并替换)不在特定HTML元素中的文本?,javascript,jquery,regex,Javascript,Jquery,Regex,TL;博士摘要 如何在当前页面的HTML中找到的特定单词或短语周围插入一个,但忽略已包含在我尝试插入的相同范围内的文本 由于要处理大量的值,这必须是高性能的 示例: 搜索“foo” 应找到匹配项: 这句话包含一个foo-bar值 如果未找到匹配项: 这句话包含一个foo-bar值 背景-即为什么? 我正在研究一个特定的问题,即必须在页面上动态找到的特定文本周围注入元素。我正在寻找的文本是一个大数组 要查找的文本字符串数组以千为单位 文本值可以包含短语或单词 短语必须优先于单词 最后一个是个杀
- 要查找的文本字符串数组以千为单位
- 文本值可以包含短语或单词
- 短语必须优先于单词
- 我有两个价值观“foo bar”和“foo”
- 我想处理这个句子:“这是一个foo-bar句子”
现在。。实现这一点的第一步是按长度对数组排序(首先处理最长的数组)。但问题是,在处理“查找-替换”逻辑后,仍在(已处理的)短语中查找较小的“单词”。如果且仅当没有嵌套的
-标记时,您可以搜索
/(]*>[\s\s]*?)|(\b(?:foo | bar)(?:\s+(?:foo | bar))*)/g
并用函数替换它
function matchEvaluator(_, span, word) {
if (span) return span;
return '<span class="widget">' + word + '</span>';
}
好的,还有一种方法 我使用jQuery查找元素(实际上不需要,但很方便)。 此解决方案接受嵌套的
,可能速度更快。请分享你的结果
(函数(){
var testwords_rx=/\b(?:foo | bar)\b///这很烦人,但应该更快
变量词_rx=/\b(?:foo | bar)\b(?::::::foo | bar)\b)?/g;
函数filterTextElement(idx,element){
返回元素!=null&&
element.nodeType==3&&/#文本节点
element.nodeValue.match(testwords_rx);//至少查找一个匹配项
}
函数wrapFoobars(idx,元素){
var-lastPos=0;
var text=element.nodeValue;
var parent=element.parentNode;
函数addUnwrapped(开始、结束){
var textNode=document.createTextNode(text.substring(start,end));
parent.insertBefore(textNode,元素);
}
函数addWrapped(开始、结束){
var span=document.createElement('span');
span.className='widget';
span.style.border=“1px实心红色”;
var txtprop='textContent'中的'textContent':'innerText';
span[txtprop]=text.substring(开始、结束);
parent.insertBefore(span,element);
}
函数splitAndWrapText(字,位置){
如果(位置>最后位置){
addUnwrapped(lastPos,pos);
}
lastPos=pos+单词长度;
addWrapped(pos,lastPos);
}
text.replace(单词_rx,splitAndWrapText);
if(lastPos
它是如何工作的
选择$('body*').filter(':not(.widget.widget*))
内的所有标记并过滤掉
-元素及其所有子元素(将此更改为仅选择所需的元素).widget
获取匹配元素的所有子元素(包括文本节点).contents()
筛选以仅获取包含至少一个搜索词的#文本元素.filter(filterTextElement)
: 把火柴换掉。第一个匹配之前、最后一个匹配之间和最后一个匹配之后的文本必须作为文本节点插入(wrapFoobars
),匹配的文本本身被包装到新创建的addUnwrapped
-元素(
)中。 最后,删除原始文本元素(addWrapped
)parent.removeChild(元素);
matchEvaluator
函数中返回不变的跨度。此外,它与您搜索的单词相匹配(不在span中!),这些单词将以
格式返回。因此,我认为它符合您的要求……我还需要匹配出现在具有不同类别的其他跨度中的单词。如果您可以确保它是
(或其他固定形式),您可以通过将]*>
替换为
来解决它。为了更通用一些,您可以使用例如]*?class=[''''][^']*?\bwidget\b[^>]+>
var texts = [
"This is a foo bar sentence",
"This sentence contains a <span class='widget'>foo bar</span> value"
];
var wordsOutsideSpan_rx = /(<span\b[^>]*>[\s\S]*?<\/span>)|(\b(?:foo|bar)(?:\s+(?:foo|bar))*)/g;
function wrapInSpan(_, span, word) {
if (span) return span;
return '<span class="widget">' + word + '</span>';
}
texts.forEach(function (txt) {
console.log(txt.replace(wordsOutsideSpan_rx, wrapInSpan));
});
// outputs
// "This is a <span class="widget">foo bar</span> sentence"
// "This sentence contains a <span class='widget'>foo bar</span> value"