Cómo encontrar / reemplazar texto en html mientras se preservan las tags / estructura html

Uso expresiones regulares para transformar el texto como quiero, pero quiero conservar las tags HTML. por ejemplo, si quiero reemplazar el “desbordamiento de stack” por “subdesbordamiento de stack”, esto debería funcionar como se esperaba: si la entrada es stack overflow , debo obtener la stack underflow La sustitución de la cadena está hecha, pero las tags siguen ahí …

Utilice una biblioteca DOM, no expresiones regulares, cuando se trata de manipular HTML:

  • lxml: un analizador, documento y serializador de HTML. También puede usar BeautifulSoup y html5lib para analizar.
  • BeautifulSoup: un analizador, un documento y un serializador de HTML.
  • html5lib: un analizador. Tiene un serializador.
  • ElementTree: un objeto de documento y un serializador XML
  • cElementTree: un objeto de documento implementado como una extensión C.
  • HTMLParser: un analizador.
  • Genshi: incluye un analizador, un documento y un serializador de HTML.
  • xml.dom.minidom: un modelo de documento integrado en la biblioteca estándar, en el que html5lib puede analizar.

Robado de http://blog.ianbicking.org/2008/03/30/python-html-parser-performance/ .

De estos, recomendaría lxml, html5lib y BeautifulSoup.

Beautiful Soup o HTMLParser es tu respuesta.

Tenga en cuenta que los reemplazos arbitrarios no se pueden hacer de forma inequívoca. Considere los siguientes ejemplos:

1)

HTML:

 AB 

Patrón -> reemplazo:

 AB -> AXB 

Posibles resultados:

 AXB AXB 

2)

HTML:

 AAA 

Patrón -> reemplazo:

 A+ -> WXYZ 

Posibles resultados:

 WXYZ WXYZ WXYZ WXYZ WXYZ WXYZ WXYZ WXYZ WXYZ WXYZ 

El tipo de algoritmos que funcione para su caso depende en gran medida de la naturaleza de los posibles patrones de búsqueda y las reglas deseadas para manejar la ambigüedad.

Use un analizador html como el proporcionado por lxml o BeautifulSoup . Otra opción es usar transformaciones XSLT ( XSLT en Jython ).

No creo que las recomendaciones de la biblioteca del analizador DOM / HTML publicadas hasta ahora aborden el problema específico en el ejemplo dado: el overflow debe reemplazarse con el overflow underflow solo cuando está precedido por la stack en el documento representado, ya sea que haya tags entre ellas o no. Sin embargo, tal biblioteca es una parte necesaria de la solución.

Suponiendo que las tags nunca aparezcan en el medio de las palabras, una solución sería

  1. procesar el DOM, tokenizar todos los nodos de texto e insertar un identificador único al principio de cada token (por ejemplo, palabra)
  2. renderizar el documento como texto plano
  3. busque y reemplace el texto simple con expresiones regulares que usan grupos para hacer coincidir, preservar y marcar identificadores únicos al comienzo de cada token
  4. extraer todos los tokens con identificadores únicos marcados del texto plano
  5. procesar el DOM eliminando identificadores únicos y reemplazando tokens que coincidan con identificadores únicos marcados con tokens cambiados correspondientes
  6. renderizar el DOM procesado de nuevo a HTML

Ejemplo:

En 1. el HTML DOM,

 stack overflow 

se convierte en el DOM

 #1;stack #2;overflow 

y en 2. se produce el texto plano:

 #1;stack #2;overflow 

La expresión regular requerida en 3. es #(\d+);stack\s+#(\d+);overflow\b y el reemplazo #\1;stack %\2;underflow . Tenga en cuenta que solo la segunda palabra se marca cambiando # a % en el identificador único, ya que la primera palabra no se modifica.

En 4., la palabra underflow con el identificador único numerado 2 se extrae del texto sin formato resultante, ya que se marcó cambiando el # a % .

En 5., todos #(\d+); Los identificadores se eliminan de los nodos de texto del DOM al buscar sus números entre las palabras extraídas. No se encuentra el número 1 , por lo que #1;stack se reemplaza simplemente con la stack . El número 2 se encuentra con la palabra modificada underflow , por lo que #2;overflow se reemplaza por underflow .

Finalmente, en 6. el DOM se vuelve a mostrar en el documento HTML `stack underflow.

Cosas divertidas para probar. Funciona sorta. A mis amigos les gusta cuando adjunto este script a un área de texto y les dejo “traducir” cosas. Supongo que podrías usarlo para cualquier cosa realmente. Meh Verifique el código varias veces si lo va a utilizar, funciona, pero soy nuevo en todo esto. Creo que han pasado 2 o tres semanas desde que comencé a estudiar el php.

 

Dear so and so, after reviewing your application I. . .

More of the same...

sincerely,

Important Dude

'); $oldWords = array('important', 'sincerely'); $newWords = array('arrogant', 'ya sure'); // function for oldWords function regex_oldWords_word_list(&$item1, $key) { $item1 = "/>([^<>]+)?\b$item1(tionally|istic|tion|ance|ence|less|ally|able|ness|ing|ity|ful|ant|est|ist|ic|al|ed|er|et|ly|y|s|d|'s|'d|'ve|'ll)?\b([^<>]+)?/"; } // function for newWords function format_newWords_results(&$item1, $key) { $item1 = ">$1 $item1$2$3"; } // apply regex to oldWords array_walk($oldWords, 'regex_oldWords_word_list'); // apply formatting to newWords array_walk($newWords, 'format_newWords_results'); //HTML is not always as perfect as we want it $poo = array('/ /', '/>([a-zA-Z\']+)/', '/'/', '/;([a-zA-Z\']+)/', '/"([a-zA-Z\']+)/', '/([a-zA-Z\']+) $1', '\'', '; $1', '" $1', '$1 <', '. crap taco.', '. crap taco with cheese.'); //and maybe things will go back to normal sort of $repoo = array('/> /', '/; /', '/" /', '/ ', ';', '"',' <'); //before echo ($html); //I don't know what was happening on the free host but I had to keep stripping slashes //This is where the work is done anyway. $html = stripslashes(preg_replace($repoo , $muck , (ucwords(preg_replace($oldWords , $newWords , (preg_replace($poo , $unpoo , (stripslashes(strtolower(stripslashes($html))))))))))); //after echo ('
' . $html); //now if only there were a way to keep it out of the area between // and and tell it that english isn't math. ?>