Ответ 1
HTML слишком сложный для надежного анализа с регулярным выражением.
Если вы хотите сделать это на стороне клиента, вы можете создать фрагмент документа и/или отключить DOM node (ни один из них нигде не отображается) и инициализировать его своей строкой HTML, а затем пройти через результирующий DOM и обрабатывать текстовые узлы. (Или используйте библиотеку, чтобы помочь вам в этом, хотя на самом деле это довольно просто.)
Здесь пример DOM. Этот пример немного проще, чем ваша проблема, потому что он просто обновляет текст, он не добавляет новые элементы в структуру (обертывание частей текста в span
включает в себя обновление структуры), но это должно вас заставить. Заметки о том, что вам нужно будет изменить в конце.
var html =
"<p>This is a test.</p>" +
"<form><input type='text' value='test value'></form>" +
"<p class='testing test'>Testing here too</p>";
var frag = document.createDocumentFragment();
var body = document.createElement('body');
var node, next;
// Turn the HTML string into a DOM tree
body.innerHTML = html;
// Walk the dom looking for the given text in text nodes
walk(body);
// Insert the result into the current document via a fragment
node = body.firstChild;
while (node) {
next = node.nextSibling;
frag.appendChild(node);
node = next;
}
document.body.appendChild(frag);
// Our walker function
function walk(node) {
var child, next;
switch (node.nodeType) {
case 1: // Element
case 9: // Document
case 11: // Document fragment
child = node.firstChild;
while (child) {
next = child.nextSibling;
walk(child);
child = next;
}
break;
case 3: // Text node
handleText(node);
break;
}
}
function handleText(textNode) {
textNode.nodeValue = textNode.nodeValue.replace(/test/gi, "TEST");
}
Изменения, которые вам нужно сделать, будут находиться в handleText
. В частности, вместо обновления nodeValue
вам необходимо:
- Найдите индекс начала каждого слова в строке
nodeValue
. - Используйте
Node#splitText
, чтобы разделить текст node на три текстовых узла (часть перед вашим соответствующим текстом, часть, которая это ваш соответствующий текст и часть, соответствующая вашему совпадающему тексту). - Используйте
document.createElement
для создания новогоspan
(это буквально простоspan = document.createElement('span')
). - Используйте
Node#insertBefore
, чтобы вставить новыйspan
перед третьим текстом node (тот, который содержит текст, следующий за вашим согласованный текст); это нормально, если вам не нужно было создавать третий node, потому что ваш сопоставленный текст был в конце текста node, просто перейдите вnull
какrefChild
. - Используйте
Node#appendChild
, чтобы переместить второй текст node (тот, у которого соответствующий текст) вspan
. (Не нужно сначала удалять его из родителя,appendChild
делает это для вас.)