2011-12-14 16 views
5

Estoy tratando de escribir un complemento de resaltado, y me gustaría conservar el formato HTML. ¿Es posible ignorar todos los caracteres entre < y> en una cadena al hacer un reemplazo usando javascript?Reemplazar palabras en una cadena, pero ignorar HTML

Utilizando el siguiente ejemplo:

var string = "Lorem ipsum dolor span sit amet, consectetuer <span class='dolor'>dolor</span> adipiscing elit."; 

Me gustaría ser capaz de lograr lo siguiente (reemplace 'dolor' con 'foo'):

var string = "Lorem ipsum FOO span sit amet, consectetuer <span class='dolor'>FOO</span> adipiscing elit."; 

O quizás incluso este (reemplace 'periodo' con 'BAR'):

var string = "Lorem ipsum dolor BAR sit amet, consectetuer <span class='dolor'>dolor</span> adipiscing elit."; 

que estuvo muy cerca de encontrar una respuesta dada por Tambler aquí: Can you ignore HTML in a string while doing a Replace with jQuery? pero, por alguna razón, simplemente no puedo lograr que funcione la respuesta aceptada.

Soy completamente nuevo en Regex, por lo que cualquier ayuda sería agradecida.

+1

http://stackoverflow.com/questions/2289552/jquery-can-you-ignore-html- in-string-while-doing-a-replace – ggzone

+0

Jon, tratando de analizar html con regex es notoriamente difícil. http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – graphicdivine

+2

Debe analizar el HTML y luego iterar recursivamente sobre cada nodo de texto. –

Respuesta

6

Analizar el HTML utilizando el analizador integrado del navegador a través de innerHTML seguido de cruce DOM es la forma sensata de hacerlo. Aquí está una respuesta basada libremente en this answer:

Demostración en directo: http://jsfiddle.net/FwGuq/1/

Código:

// Reusable generic function 
function traverseElement(el, regex, textReplacerFunc) { 
    // script and style elements are left alone 
    if (!/^(script|style)$/.test(el.tagName)) { 
     var child = el.lastChild; 
     while (child) { 
      if (child.nodeType == 1) { 
       traverseElement(child, regex, textReplacerFunc); 
      } else if (child.nodeType == 3) { 
       textReplacerFunc(child, regex); 
      } 
      child = child.previousSibling; 
     } 
    } 
} 

// This function does the replacing for every matched piece of text 
// and can be customized to do what you like 
function textReplacerFunc(textNode, regex, text) { 
    textNode.data = textNode.data.replace(regex, "FOO"); 
} 

// The main function 
function replaceWords(html, words) { 
    var container = document.createElement("div"); 
    container.innerHTML = html; 

    // Replace the words one at a time to ensure each one gets matched 
    for (var i = 0, len = words.length; i < len; ++i) { 
     traverseElement(container, new RegExp(words[i], "g"), textReplacerFunc); 
    } 
    return container.innerHTML; 
} 


var html = "Lorem ipsum dolor span sit amet, consectetuer <span class='dolor'>dolor</span> adipiscing elit."; 
alert(replaceWords(html, ["dolor"])); 
+0

Gracias por tan buena respuesta, Tim. ¡Muy apreciado! – Jon

+0

Esta es una muy buena solución, pero cuando intentas incluir etiquetas HTML en el texto de reemplazo, se escapan. Por ejemplo, doblar la cadena de búsqueda dará como resultado <cadena> – Hawkee

+0

@Hawkee: Sí. Permitir HTML en la cadena de búsqueda cambia por completo el problema. –

1

Esta solución funciona con el Perl, y también deben trabajar con Javascript, ya que es compatible con ECMA 262:

s,\bdolor\b(?=[^"'][^>]*>),FOO,g

Básicamente, reemplace si la palabra es seguida por todo lo que no es una cita, seguido por todo lo que no sea el cierre > y el cierre > sí mismo.

+0

Aunque desafortunadamente no pude hacer que tu ejemplo funcione, gracias de todos modos por tu respuesta, fge. – Jon

Cuestiones relacionadas