Expresiones regulares: La extracción (no código) texto y URLs legible desde documentos HTML

StackOverflow https://stackoverflow.com/questions/3951485

Pregunta

Estoy creando una aplicación que tendrá una URL como entrada, recuperar el contenido HTML de la página de la web y el extracto de todo lo que no está contenida en una etiqueta . En otras palabras, el contenido textual de la página, como se ve por el visitante a esa página. Eso incluye 'enmascarar' todo lo encapsuled en <script></script>, <style></style> y <!-- -->, ya que estos contienen porciones de texto que no está envuelto dentro de una etiqueta (pero es mejor no hacer nada).

he construido esta expresión regular:

(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>)

Se selecciona correctamente todo el contenido que quiero pasar por alto, y sólo deja el contenido del texto de la página. Sin embargo, eso significa que lo que quiero extracto no se mostrará en la colección partido (estoy usando VB.Net en Visual Studio 2010).

¿Hay una manera de "invertir" la coincidencia de todo un documento como este, por lo que me gustaría obtener partidos en todas las cadenas de texto que se quedan fuera por la coincidencia de la expresión regular anterior?

Hasta el momento, lo que hice fue agregar otra alternativa al final, que selecciona "cualquier secuencia que no contiene ", lo que significa, entonces, el texto sobrante. Nombré que el último bit de un grupo de captura, y cuando iterar sobre los partidos, puedo comprobar la presencia de texto en el grupo de "texto". Esto funciona, pero me preguntaba si era posible hacerlo todo a través de expresiones regulares y solo terminan con partidos en el texto sin formato.

Esto se supone que funciona de forma genérica, sin saber las etiquetas específicas en el html. Se supone que el extracto de todos texto. Además, necesito preservar el HTML original para que la página se reserva todos sus enlaces y scripts - Sólo tengo que ser capaz de extraer el texto para que pueda realizar búsquedas y reemplazos dentro de ella, sin temor a "Cambio de nombre" ninguna etiqueta, atributos o variables de proceso, etc. (lo que no puedo acaba de hacer una "reemplazar con nada" en todos los partidos que recibo, porque a pesar de que estoy luego a la izquierda, con lo que necesito, que es una molestia para reinsertar que de nuevo en los lugares correctos del documento completamente funcional).

Quiero saber si esto es posible en absoluto el uso de expresiones regulares (y sé acerca de HTML agilidad paquete y XPath, pero no me siento como).

¿Alguna sugerencia?

Actualización: Aquí está la solución (basado en expresiones regulares) que terminó con: http://www.martinwardener.com/regex/ , implementado en una aplicación web demo que mostrará tanto las cadenas de expresiones regulares activo junto con un motor experimental que le permite ejecutar el análisis en cualquier página hTML en línea, lo que le pARSE veces y los resultados extraídos (por enlace, URL y el texto porciones individualmente -., así como vistas donde todos los partidos de expresiones regulares se destacan en su lugar en el documento HTML completa)

¿Fue útil?

Solución 5

OK, así que aquí está cómo lo estoy haciendo:

Usando mi expresión regular original (con el patrón de búsqueda añadido para el texto plano, que pasa a ser cualquier texto que sobra después de la etiqueta búsquedas se realizan):

(?:(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?P<text>[^<>]*)

A continuación, en VB.Net:

Dim regexText As New Regex("(?:(?:<(?<tag>script|style)[\s\S]*?</\k<tag>>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?<text>[^<>]*)", RegexOptions.IgnoreCase)
Dim source As String = File.ReadAllText("html.txt")
Dim evaluator As New MatchEvaluator(AddressOf MatchEvalFunction)
Dim newHtml As String = regexText.Replace(source, evaluator)

El actual sustitución de texto que pasa aquí:

Private Function MatchEvalFunction(ByVal match As Match) As String
    Dim plainText As String = match.Groups("text").Value
    If plainText IsNot Nothing AndAlso plainText <> "" Then
        MatchEvalFunction = match.Value.Replace(plainText, plainText.Replace("Original word", "Replacement word"))
    Else
        MatchEvalFunction = match.Value
    End If
End Function

Voila. newHtml ahora contiene un copia exacta del original, excepto todas las apariciones de "palabra original" en la página (como se presenta en un navegador) se conecta con la "palabra de sustitución", y todo el código HTML y script se conserva intacta. Por supuesto, se podría / pondría en una rutina de reemplazo más elaborado, pero esto muestra el principio básico. Se trata de 12 líneas de código, incluyendo declaración de la función y la carga de código html, etc. Yo estaría muy interesado en ver una solución en paralelo, hecho en DOM, etc para la comparación (sí, sé que este enfoque se puede perder el equilibrio por seguro ocurrencias de algunas peculiaridades Etiquetas anidadas - en escritura reescritura - pero el daño de que todavía va a ser muy limitados, en su caso (ver algunos de los comentarios anteriores), y, en general, esto va a hacer el trabajo bastante maldito bien ).

Otros consejos

lo que hice fue añadir otra alternativa en el extremo, que selecciona "cualquier secuencia que no contiene < o >", que significa, entonces, el texto sobrante. Nombré que el último bit de un grupo de captura, y cuando iterar sobre los partidos, puedo comprobar la presencia de texto en el grupo de "texto".

Eso es lo que normalmente lo haría. O aún más simple, reemplazar cada coincidencia del patrón marcado con y cadena vacía y lo que me queda es la materia que usted está buscando.

tipo de obras, pero no parece ser una cadena aquí y allá que es recogido que no debería ser.

Bueno, sí, eso es debido a que su expresión y la expresión regular, en general, es inadecuado para analizar HTML válido incluso, por no hablar de los horrores que están ahí fuera en la web real. Primer consejo a la vista, si realmente desea perseguir este enfoque inútil:. (Valores de atributos, así como el contenido de texto en general) puede contener un carácter > sin escape

Me gustaría sugerir una vez más los beneficios de la agilidad HTML paquete.

ETA:. Ya que parece que quererlo, he aquí algunos ejemplos de marcado que parece que va a tropezar su expresión

<a href=link></a> - unquoted
<a href= link></a> - unquoted, space at front matched but then required at back
<a href="~/link"></a> - very common URL char missing in group
<a href="link$!*'link"></a> - more URL chars missing in group
<a href=lïnk></a> - IRI
<a href
    ="link"> - newline (or tab)
<div style="background-image: url(link);"> - unquoted
<div style="background-image: url( 'link' );"> - spaced
<div style="background-image: u&#114;l('link');"> - html escape
<div style="background-image: ur\l('link');"> - css escape
<div style="background-image: url('link\')link');"> - css escape
<div style="background-image: url(\
'link')"> - CSS folding
<div style="background-image: url
('link')"> - newline (or tab)

y que está marcado acaba completamente válido que no que coincida con el enlace de la derecha, no es posible ninguna de las marcas inválidas, de marcado que no debería, pero que coincida con un enlace, o cualquiera de los muchos problemas con su otra técnica de marcado división del texto. Esta es la punta del iceberg.

Regex no es fiable para recuperar contenido textual de los documentos HTML. Expresiones regulares no puede manejar etiquetas anidadas. Suponiendo que un documento no contiene ninguna etiqueta anidada, expresiones regulares todavía requiere cada etiquetas están correctamente cerradas.

Si está usando PHP, por simplicidad, te recomendamos utilizar DOM (Document Object Model) para analizar los documentos HTML / extracto. DOM biblioteca generalmente existe en cualquier lenguaje de programación.

Si usted está mirando para partes de extracto de una cadena, y no incluya una expresión regular, usted podría simplemente reemplazar las partes que son emparejado con una cadena vacía para el mismo efecto.

Tenga en cuenta que la única razón de que esto se debe a que la fuerza de trabajo de las etiquetas que estamos interesados ??en eliminar, etiquetas <script> y <style>, no se pueden anidar.

Sin embargo, no es raro que una etiqueta <script> que contiene código para programación de agregación otra etiqueta <script>, en cuyo caso su expresión regular fallará. También se producirá un error en el caso de que cualquier etiqueta no está bien cerrada.

No se puede analizar HTML con expresiones regulares.

análisis de HTML con expresiones regulares conduce a la tristeza.

Yo sé que sólo estás haciendo por diversión, pero hay tantos paquetes que hay que hacer realidad el análisis de la manera correcta, y hacerlo de forma fiable, y han sido probados.

No vaya a reinventar la rueda, y hacerlo de una manera que es casi garantizado para frustrar usted en el camino.

Para su información,

En lugar de expresiones regulares, con jQuery, Su posible para extraer el texto de un solo formato HTML. Para que se puede utilizar el siguiente patrón.

$("<div/>").html("#elementId").text()

Puede remitir este jsFiddle

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top