Javascript Regex per sostituire il testo NON in attributi html

Vorrei un Regex Javascript per racchiudere un determinato elenco di parole in un dato inizio ( ) e tag finale (cioè ), ma solo se la parola è in realtà “testo visibile” nella pagina, e non all’interno di un attributo html (come il tag title di un link o all’interno di un blocco .

Ho creato un JS Fiddle con le impostazioni di base: http://jsfiddle.net/4YCR6/1/

L’HTML è troppo complesso per analizzare in modo affidabile un’espressione regolare.

Se stai cercando di fare questo lato client, puoi creare un frammento di documento e / o nodo DOM disconnesso (nessuno dei quali è visualizzato da nessuna parte) e inizializzarlo con la tua stringa HTML, quindi camminare attraverso la struttura DOM risultante ed elaborare il nodes di testo. (Oppure usa una libreria per aiutarti a farlo, anche se in realtà è piuttosto semplice).

Ecco un esempio di DOM walking. Questo esempio è leggermente più semplice del tuo problema perché aggiorna semplicemente il testo, non aggiunge nuovi elementi alla struttura (il wrapping di parti del testo in cui è coinvolto l’aggiornamento della struttura), ma dovrebbe farti andare avanti. Note su cosa devi cambiare alla fine.

 var html = "

This is a test.

" + "
" + "

Testing here too

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

Esempio dal vivo

Le modifiche che dovrai apportare saranno in handleText . In particolare, anziché aggiornare nodeValue , dovrai:

  • Trova l’indice dell’inizio di ogni parola all’interno della stringa nodeValue .
  • Usa Node#splitText per dividere il nodo di testo in un massimo di tre nodes di testo (la parte prima del testo corrispondente, la parte che corrisponde al testo corrispondente e la parte che segue il testo corrispondente).
  • Usa document.createElement per creare il nuovo span (questo è letteralmente solo span = document.createElement('span') ).
  • Usa Node#insertBefore insert Node#insertBefore di inserire la nuova span davanti al terzo nodo di testo (quello contenente il testo che segue il testo corrispondente); va bene se non è necessario creare un terzo nodo perché il testo corrispondente era alla fine del nodo di testo, basta passare in null come refChild .
  • Usa Node#appendChild per spostare il secondo nodo di testo (quello con il testo corrispondente) nello span . (Non è necessario rimuoverlo dal suo genitore prima, appendChild fa per te.)

La risposta di TJ Crowder è corretta. Sono andato un po ‘più in termini di codice: ecco un esempio completo che funziona in tutti i principali browser. Ho pubblicato varianti di questo codice su Stack Overflow prima ( qui e qui , ad esempio), e l’ho reso bello e generico, così io (o chiunque altro) non devo cambiarlo molto per riutilizzarlo.

Esempio jsFiddle: http://jsfiddle.net/7Vf5J/38/

Codice:

 // Reusable generic function function surroundInElement(el, regex, surrounderCreateFunc) { // script and style elements are left alone if (!/^(script|style)$/.test(el.tagName)) { var child = el.lastChild; while (child) { if (child.nodeType == 1) { surroundInElement(child, regex, surrounderCreateFunc); } else if (child.nodeType == 3) { surroundMatchingText(child, regex, surrounderCreateFunc); } child = child.previousSibling; } } } // Reusable generic function function surroundMatchingText(textNode, regex, surrounderCreateFunc) { var parent = textNode.parentNode; var result, surroundingNode, matchedTextNode, matchLength, matchedText; while ( textNode && (result = regex.exec(textNode.data)) ) { matchedTextNode = textNode.splitText(result.index); matchedText = result[0]; matchLength = matchedText.length; textNode = (matchedTextNode.length > matchLength) ? matchedTextNode.splitText(matchLength) : null; // Ensure searching starts at the beginning of the text node regex.lastIndex = 0; surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true)); parent.insertBefore(surroundingNode, matchedTextNode); parent.removeChild(matchedTextNode); } } // This function does the surrounding for every matched piece of text // and can be customized to do what you like function createSpan(matchedTextNode) { var el = document.createElement("span"); el.style.color = "red"; el.appendChild(matchedTextNode); return el; } // The main function function wrapWords(container, words) { // Replace the words one at a time to ensure "test2" gets matched for (var i = 0, len = words.length; i < len; ++i) { surroundInElement(container, new RegExp(words[i]), createSpan); } } wrapWords(document.getElementById("container"), ["test2", "test"]);