Я анализирую всю строку в элемент DOM, а затем go через все элементы span, чтобы изменить их содержимое с «an» на «a». Метасимвол \b
в регулярном выражении обозначает границу слова.
Редактировать:
После более глубокого копания я могу теперь работать со всеми текстовыми узлами и изменять соответствующие строки:
var html='<div> an <span> is an </span>apple and this <span> is a </span> banana.</div>';
var b=document.createElement('body');
b.innerHTML=html;
// use the "optional filter function" to do the changes:
getTextNodesIn(b,n=>n.textContent=n.textContent.replace(/\ban\b/g,'a'));
// output:
console.log(b.innerHTML);
// I just realised that I can also use Chris West's original function:
// https://cwestblog.com/2014/03/14/javascript-getting-all-text-nodes/
function getTextNodesIn(elem, opt_fnFilter) {
var textNodes = [];
if (elem) {
for (var nodes = elem.childNodes, i = nodes.length; i--;) {
var node = nodes[i], nodeType = node.nodeType;
if (nodeType == 3) {
if (!opt_fnFilter || opt_fnFilter(node, elem)) {
textNodes.push(node);
}
}
else if (nodeType == 1 || nodeType == 9 || nodeType == 11) {
textNodes = textNodes.concat(getTextNodesIn(node, opt_fnFilter));
}
}
}
return textNodes;
}
«Интересный факт»: в нотации ES6 функция может быть переписана еще более коротким способом:
function getTN(elem, opt_flt) {
if (elem) return [...elem.childNodes].reduce((tn,node)=>{
var nty = node.nodeType;
if (nty==3 && (!opt_flt || opt_flt(node, elem))) tn.push(node);
else if (nty==1 || nty==9 || nty==11) tn=tn.concat(getTN(node, opt_flt));
return tn
}, []);
}