Usar expresiones regulares para analizar HTML: ¿por qué no?

208

Parece que cada pregunta en stackoverflow donde el autor de la pregunta está utilizando expresiones regulares para obtener cierta información de HTML inevitablemente tendrá una "respuesta" que dice no usar expresiones regulares para analizar HTML.

Por qué no? Soy consciente de que existen analizadores HTML "reales" entre comillas, como Beautiful Soup , y estoy seguro de que son potentes y útiles, pero si solo estás haciendo algo simple, rápido o sucio, ¿por qué? ¿te molestas en usar algo tan complicado cuando unas pocas declaraciones de expresiones regulares funcionarán bien?

Además, ¿hay algo fundamental que no entiendo sobre la expresión regular que los convierte en una mala opción para analizar en general?

ntownsend
fuente
3
Creo que este es un engaño de stackoverflow.com/questions/133601
jcrossley3
23
Porque solo Chuck Norris puede analizar HTML con expresiones regulares (como se explica en esta famosa cosa de Zalgo: stackoverflow.com/questions/1732348/… ).
takeshin
1
Esta pregunta me llevó a preguntar otra que de alguna manera está relacionada. En caso de que le interese: ¿Por qué no es posible utilizar expresiones regulares para analizar HTML / XML: una explicación formal en términos simples
Mac
Cuidado con Zalgo
Kelly S. French
Esta pregunta se ha agregado a las Preguntas frecuentes sobre Expresión regular de desbordamiento de pila , en "Tareas de validación comunes".
aliteralmind

Respuestas:

212

El análisis completo de HTML no es posible con expresiones regulares, ya que depende de la coincidencia de la etiqueta de apertura y cierre que no es posible con expresiones regulares.

Las expresiones regulares solo pueden coincidir con los lenguajes regulares, pero HTML es un lenguaje libre de contexto y no un lenguaje regular (como señaló @StefanPochmann, los lenguajes regulares también están libres de contexto, por lo que no necesariamente significa no regular). Lo único que puede hacer con expresiones regulares en HTML es la heurística, pero eso no funcionará en todas las condiciones. Debería ser posible presentar un archivo HTML que coincida incorrectamente con cualquier expresión regular.

Johannes Weiss
fuente
26
La mejor respuesta hasta ahora. Si solo puede coincidir con las gramáticas regulares, necesitaríamos una expresión regular infinitamente grande para analizar una gramática libre de contexto como HTML. Me encanta cuando estas cosas tienen respuestas teóricas claras.
ntownsend
2
Asumí que estábamos discutiendo expresiones regulares de tipo Perl donde en realidad no son expresiones regulares.
Hank Gay
55
En realidad, las expresiones regulares .Net pueden hacer coincidir las etiquetas de apertura con las de cierre, hasta cierto punto, utilizando grupos de equilibrio y una expresión cuidadosamente elaborada. Contar con todo eso en una expresión regular sigue siendo una locura, por supuesto, se vería como el gran código Chtulhu y probablemente también invocaría el verdadero. Y al final todavía no funcionará en todos los casos. Dicen que si escribe una expresión regular que pueda analizar correctamente cualquier HTML, el universo colapsará sobre sí mismo.
Alex Paven
55
Algunas bibliotecas de expresiones regulares pueden hacer expresiones regulares recursivas (convirtiéndolas efectivamente en expresiones no regulares :)
Ondra Žižka
43
-1 Esta respuesta saca la conclusión correcta ("Es una mala idea analizar HTML con Regex") a partir de argumentos incorrectos ("Porque HTML no es un lenguaje normal"). Lo que la mayoría de las personas hoy en día quieren decir cuando dicen "regex" (PCRE) es muy capaz no solo de analizar gramáticas libres de contexto (eso es realmente trivial), sino también de gramáticas sensibles al contexto (ver stackoverflow.com/questions/7434272/ ... )
NikiC
35

Para regexp rápido y sucio, estará bien. Pero lo fundamental es saber que es imposible construir una expresión regular que analice correctamente HTML.

La razón es que las expresiones regulares no pueden manejar expresiones anidadas arbitrariamente. Consulte ¿Se pueden usar expresiones regulares para unir patrones anidados?

kmkaplan
fuente
1
Algunas bibliotecas de expresiones regulares pueden hacer expresiones regulares recursivas (haciéndolas efectivamente expresiones no regulares :)
Ondra Žižka
23

(De http://htmlparsing.com/regexes )

Supongamos que tiene un archivo HTML en el que intenta extraer URL de etiquetas <img>.

<img src="http://example.com/whatever.jpg">

Entonces escribes una expresión regular como esta en Perl:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

En este caso, de $urlhecho contendrá http://example.com/whatever.jpg. Pero, ¿qué sucede cuando comienzas a obtener HTML como este?

<img src='http://example.com/whatever.jpg'>

o

<img src=http://example.com/whatever.jpg>

o

<img border=0 src="http://example.com/whatever.jpg">

o

<img
    src="http://example.com/whatever.jpg">

o comienzas a obtener falsos positivos de

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

Parece tan simple, y podría ser simple para un archivo único e inmutable, pero para cualquier cosa que vaya a hacer con datos HTML arbitrarios, las expresiones regulares son solo una receta para futuros dolores de cabeza.

Andy Lester
fuente
44
Esta parece ser la respuesta real, aunque probablemente sea posible analizar HTML arbitrario con regex ya que las expresiones regulares de hoy son más que un simple autómata finito, para analizar html arbitrario y no solo una página concreta, debe volver a implementar un analizador HTML en regexp y las expresiones regulares seguramente se vuelven 1000 veces ilegibles.
Smit Johnth
1
Hola Andy, me tomé el tiempo para crear una expresión que respalde tus casos mencionados. stackoverflow.com/a/40095824/1204332 ¡Déjame saber lo que piensas! :)
Ivan Chaer
2
El razonamiento en esta respuesta está muy desactualizado y se aplica aún menos hoy de lo que lo hizo originalmente (lo que creo que no fue así). (Citando OP: "si solo estás haciendo algo simple, rápido o sucio ...")
Sz.
16

Dos razones rápidas:

  • escribir una expresión regular que pueda resistir la entrada maliciosa es difícil; mucho más difícil que usar una herramienta preconstruida
  • escribir una expresión regular que pueda funcionar con el marcado ridículo con el que inevitablemente se quedará atrapado es difícil; mucho más difícil que usar una herramienta preconstruida

En cuanto a la idoneidad de las expresiones regulares para el análisis en general: no son adecuadas. ¿Alguna vez has visto los tipos de expresiones regulares que necesitarías para analizar la mayoría de los idiomas?

Hank Gay
fuente
2
¿Guau? ¿Un voto negativo después de más de 2 años? En caso de que alguien se preguntara, no dije "Porque es teóricamente imposible" porque la pregunta claramente se hizo sobre "rápido y sucio", no "correcto". El OP claramente ya leyó respuestas que cubrían el territorio teóricamente imposible y aún no estaba satisfecho.
Hank Gay
1
Tener un voto positivo después de más de 5 años. :) En cuanto a por qué podría haber recibido el voto negativo, no estoy calificado para decirlo, pero personalmente, me hubiera gustado ver algunos ejemplos o explicaciones en lugar de la pregunta retórica de cierre.
Adam Jensen
3
Esencialmente, todo el análisis html rápido y sucio que se realiza en el envío de productos o herramientas internas termina siendo un gran agujero de seguridad o un error a la espera de que suceda. Debe desanimarse con gusto. Si se puede usar una expresión regular, se puede usar un analizador html adecuado.
Vuelva a instalar Mónica
16

En cuanto al análisis, las expresiones regulares pueden ser útiles en la etapa de "análisis léxico" (lexer), donde la entrada se divide en tokens. Es menos útil en la etapa real de "construir un árbol de análisis".

Para un analizador de HTML, esperaría que solo acepte HTML bien formado y eso requiere capacidades fuera de lo que puede hacer una expresión regular (no pueden "contar" y asegurarse de que un número dado de elementos de apertura estén equilibrados por el mismo número de elementos de cierre).

Vatine
fuente
8

Debido a que hay muchas maneras de "fastidiar" HTML que los navegadores tratarán de una manera bastante liberal, pero tomaría bastante esfuerzo reproducir el comportamiento liberal del navegador para cubrir todos los casos con expresiones regulares, por lo que su expresión regular inevitablemente fallará en alguna especial casos, y eso posiblemente introduciría serias brechas de seguridad en su sistema.

Tamas Czinege
fuente
1
Muy cierto, la mayoría del HTML parece ser horrible. No entiendo cómo una expresión regular que falla puede introducir serias brechas de seguridad. ¿Puede dar un ejemplo?
ntownsend
44
ntownsend: Por ejemplo, cree que ha eliminado todas las etiquetas de script del HTML, pero su expresión regular falla y cubre un caso especial (que, digamos, solo funciona en IE6): ¡boom, tiene una vulnerabilidad XSS!
Tamas Czinege
1
Este fue un ejemplo estrictamente hipotético, ya que la mayoría de los ejemplos del mundo real son demasiado complicados para encajar en estos comentarios, pero podría encontrar algunos buscando rápidamente en Google sobre el tema.
Tamas Czinege
3
+1 por mencionar el ángulo de seguridad. Cuando interactúas con todo el Internet, no puedes permitirte escribir código hacky "funciona la mayor parte del tiempo".
j_random_hacker
7

El problema es que la mayoría de los usuarios que hacen una pregunta que tiene que ver con HTML y expresiones regulares hacen esto porque no pueden encontrar una expresión regular propia que funcione. Entonces uno tiene que pensar si todo sería más fácil cuando se usa un analizador DOM o SAX o algo similar. Están optimizados y construidos con el propósito de trabajar con estructuras de documentos similares a XML.

Claro, hay problemas que se pueden resolver fácilmente con expresiones regulares. Pero el énfasis se encuentra fácilmente .

Si solo desea encontrar todas las URL que parecen http://.../estar bien con expresiones regulares. Pero si desea encontrar todas las URL que están en un elemento a que tiene la clase 'mylink', probablemente sea mejor usar un analizador apropiado.

okoman
fuente
6

Las expresiones regulares no se diseñaron para manejar una estructura de etiqueta anidada, y en el mejor de los casos es complicado (en el peor de los casos, imposible) manejar todos los casos extremos posibles que se obtienen con HTML real.

Peter Boughton
fuente
6

Creo que la respuesta está en la teoría de la computación. Para que un lenguaje sea analizado usando regex debe ser por definición "regular" ( enlace ). HTML no es un lenguaje regular ya que no cumple con una serie de criterios para un lenguaje regular (mucho que ver con los muchos niveles de anidamiento inherentes en el código html). Si está interesado en la teoría de la computación, le recomendaría este libro.

etiquetadores
fuente
1
De hecho, he leído ese libro. Simplemente no se me ocurrió que HTML es un lenguaje sin contexto.
ntownsend
4

Esta expresión recupera atributos de elementos HTML. Soporta:

  • atributos sin comillas / comillas,
  • comillas simples / dobles,
  • comillas escapadas dentro de los atributos,
  • espacios alrededor de signos iguales,
  • cualquier cantidad de atributos,
  • verifique solo los atributos dentro de las etiquetas,
  • comentarios de escape, y
  • gestionar diferentes cotizaciones dentro de un valor de atributo.

(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)

Compruébelo usted mismo . Funciona mejor con las banderas "gisx", como en la demostración.

Ivan Chaer
fuente
1
Eso es muy interesante. No legible, probablemente difícil de depurar pero aún así: ¡trabajo impresionante!
Eric Duminil
Esto todavía asume vagamente que el HTML está bien formado. Sin la coincidencia de contexto, esto coincidirá con las URL aparentes en contextos en los que normalmente no desea que coincidan, como en un fragmento de código JavaScript dentro de una <script>etiqueta.
tripleee
4

HTML / XML se divide en marcado y contenido. Regex solo es útil haciendo un análisis de etiqueta léxica. Supongo que podrías deducir el contenido. Sería una buena opción para un analizador SAX. Las etiquetas y el contenido se pueden entregar a una función definida por el usuario donde se puede realizar un seguimiento de la anidación / cierre de elementos.

En cuanto al análisis de las etiquetas, puede hacerse con expresiones regulares y usarse para quitar etiquetas de un documento.

Durante años de pruebas, he encontrado el secreto de la forma en que los navegadores analizan las etiquetas, tanto bien como mal formadas.

Los elementos normales se analizan con esta forma:

El núcleo de estas etiquetas usa esta expresión regular

 (?:
      " [\S\s]*? " 
   |  ' [\S\s]*? ' 
   |  [^>]? 
 )+

Notarás esto [^>]?como una de las alternancias. Esto coincidirá con citas desequilibradas de etiquetas mal formadas.

También es la raíz más simple de todo mal para las expresiones regulares. La forma en que se usa provocará un golpe para satisfacer su codicioso contenedor cuantificado que debe coincidir.

Si se usa de forma pasiva, nunca hay un problema. Pero, si obliga a que algo coincida al intercalarlo con un par de atributo / valor deseado, y no proporciona la protección adecuada contra el retroceso, es una pesadilla fuera de control.

Esta es la forma general de las etiquetas antiguas simples. Observe que [\w:]representa el nombre de la etiqueta? En realidad, los caracteres legales que representan el nombre de la etiqueta son una lista increíble de caracteres Unicode.

 <     
 (?:
      [\w:]+ 
      \s+ 
      (?:
           " [\S\s]*? " 
        |  ' [\S\s]*? ' 
        |  [^>]? 
      )+
      \s* /?
 )
 >

Continuando, también vemos que simplemente no puede buscar una etiqueta específica sin analizar TODAS las etiquetas. Quiero decir que podrías, pero tendría que usar una combinación de verbos como (* SKIP) (* FAIL) pero aún así todas las etiquetas deben analizarse.

La razón es que la sintaxis de la etiqueta puede estar oculta dentro de otras etiquetas, etc.

Por lo tanto, para analizar pasivamente todas las etiquetas, se necesita una expresión regular como la siguiente. Este particular también coincide con contenido invisible .

A medida que nuevos HTML o xml o cualquier otro desarrollen nuevas construcciones, simplemente agréguelo como una de las alternancias.


Nota de la página web: nunca he visto una página web (o xhtml / xml) con la que haya
tenido problemas. Si encuentras uno, házmelo saber.

Nota de rendimiento: es rápido. Este es el analizador de etiquetas más rápido que he visto
(puede haber más rápido, quién sabe).
Tengo varias versiones específicas También es excelente como raspador
(si eres del tipo práctico).


Completa expresión regular cruda

<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>

Aspecto formateado

 <
 (?:
      (?:
           (?:
                # Invisible content; end tag req'd
                (                             # (1 start)
                     script
                  |  style
                  |  object
                  |  embed
                  |  applet
                  |  noframes
                  |  noscript
                  |  noembed 
                )                             # (1 end)
                (?:
                     \s+ 
                     (?>
                          " [\S\s]*? "
                       |  ' [\S\s]*? '
                       |  (?:
                               (?! /> )
                               [^>] 
                          )?
                     )+
                )?
                \s* >
           )

           [\S\s]*? </ \1 \s* 
           (?= > )
      )

   |  (?: /? [\w:]+ \s* /? )
   |  (?:
           [\w:]+ 
           \s+ 
           (?:
                " [\S\s]*? " 
             |  ' [\S\s]*? ' 
             |  [^>]? 
           )+
           \s* /?
      )
   |  \? [\S\s]*? \?
   |  (?:
           !
           (?:
                (?: DOCTYPE [\S\s]*? )
             |  (?: \[CDATA\[ [\S\s]*? \]\] )
             |  (?: -- [\S\s]*? -- )
             |  (?: ATTLIST [\S\s]*? )
             |  (?: ENTITY [\S\s]*? )
             |  (?: ELEMENT [\S\s]*? )
           )
      )
 )
 >
tripleee
fuente
3

"Depende" sin embargo. Es cierto que las expresiones regulares no pueden y no pueden analizar HTML con verdadera precisión, por todas las razones dadas aquí. Sin embargo, si las consecuencias de equivocarse (como no manejar etiquetas anidadas) son menores, y si las expresiones regulares son muy convenientes en su entorno (como cuando está pirateando Perl), continúe.

Supongamos que está analizando páginas web que enlazan a su sitio, tal vez las encontró con una búsqueda de enlaces de Google, y desea una forma rápida de tener una idea general del contexto que rodea su enlace. Está intentando ejecutar un pequeño informe que podría alertarlo para vincular el correo no deseado, algo así.

En ese caso, analizar mal algunos de los documentos no será un gran problema. Nadie más que usted verá los errores, y si tiene mucha suerte, habrá pocos suficientes para que pueda hacer un seguimiento individualmente.

Supongo que estoy diciendo que es una compensación. A veces, implementar o usar un analizador correcto, por más fácil que sea, podría no valer la pena si la precisión no es crítica.

Solo ten cuidado con tus suposiciones. Puedo pensar en algunas formas en que el acceso directo regexp puede ser contraproducente si está tratando de analizar algo que se mostrará en público, por ejemplo.

comida de gato
fuente
3

Definitivamente, hay casos en los que usar una expresión regular para analizar parte de la información de HTML es la forma correcta de hacerlo: depende mucho de la situación específica.

El consenso anterior es que, en general, es una mala idea. Sin embargo, si se conoce la estructura HTML (y es poco probable que cambie), sigue siendo un enfoque válido.

Jason
fuente
3

Tenga en cuenta que si bien el HTML en sí no es regular, las partes de una página que está viendo podrían ser regulares.

Por ejemplo, es un error que las <form>etiquetas se aniden; Si la página web funciona correctamente, <form>sería razonable utilizar una expresión regular para obtener una .

Recientemente hice un poco de raspado web usando solo selenio y expresiones regulares. Llegué con la suya porque los datos que quería era poner en una <form>, y pusieron en un formato de tabla simple (de modo que pudiera contar con <table>, <tr>y <td>como no anidados - que en realidad es muy poco común). En cierto grado, las expresiones regulares eran incluso casi necesarias, porque parte de la estructura a la que necesitaba acceder estaba delimitada por comentarios. (Beautiful Soup puede darle comentarios, pero hubiera sido difícil agarrar <!-- BEGIN -->y <!-- END -->bloquear usando Beautiful Soup).

Sin embargo, si tuviera que preocuparme por las tablas anidadas, ¡mi enfoque simplemente no hubiera funcionado! Hubiera tenido que recurrir a Beautiful Soup. Incluso entonces, sin embargo, a veces puedes usar una expresión regular para agarrar el fragmento que necesitas y luego profundizar desde allí.

alfeo
fuente
2

En realidad, el análisis HTML con expresiones regulares es perfectamente posible en PHP. Solo tiene que analizar toda la cadena hacia atrás usando strrpospara buscar <y repetir la expresión regular a partir de ahí usando especificadores no greedy cada vez para superar las etiquetas anidadas. No es lujoso y terriblemente lento en cosas grandes, pero lo usé para mi propio editor de plantillas personales para mi sitio web. En realidad no estaba analizando HTML, pero hice algunas etiquetas personalizadas para consultar las entradas de la base de datos para mostrar tablas de datos (mi <#if()>etiqueta podría resaltar entradas especiales de esta manera). No estaba preparado para un analizador XML en solo un par de etiquetas auto creadas (con datos muy distintos de XML) aquí y allá.

Entonces, aunque esta pregunta está considerablemente muerta, todavía aparece en una búsqueda en Google. Lo leí y pensé "desafío aceptado" y terminé de arreglar mi código simple sin tener que reemplazarlo todo. Decidí ofrecer una opinión diferente a cualquiera que busque una razón similar. Además, la última respuesta se publicó hace 4 horas, por lo que sigue siendo un tema candente.

Deji
fuente
2
-1 por sugerir una idea TERRIBLE. ¿Consideró el espacio en blanco entre la etiqueta y el paréntesis angular de cierre? (Por ejemplo, <tag >) ¿Consideró las etiquetas de cierre comentadas? (Por ejemplo, <tag> <!-- </tag> -->) ¿Consideraste CDATA? ¿Consideró las etiquetas de caso inconsistente? (Ej. <Tag> </tAG>) ¿Consideraste esto también?
rmunn
1
En el caso particular de sus pocas etiquetas personalizadas, sí, las expresiones regulares funcionan bien. Entonces, no es que su uso de ellos haya sido un error en su caso particular . Sin embargo, eso no es HTML, y decir "el análisis HTML con expresiones regulares es perfectamente posible en PHP" es simplemente falso y una idea TERRIBLE. Las inconsistencias del HTML real (y hay muchas más que las pocas que enumeré) son la razón por la que nunca debe analizar HTML real con expresiones regulares. Vea, bueno, todas las otras respuestas a esta pregunta, así como la que he vinculado en mi otro comentario anterior.
rmunn
2
PHP es un lenguaje completo, por lo que no es falso en absoluto. Todo lo que sea computacionalmente posible es posible, incluido el análisis de HTML. Los espacios en las etiquetas NUNCA fueron un problema y desde entonces lo he adaptado para enumerar los elementos de la etiqueta en orden. Mi uso corrigió automáticamente las etiquetas con una carcasa inconsistente, cosas comentadas despojadas en la primera etapa y después de algunas adiciones posteriores se pueden agregar fácilmente todo tipo de etiquetas (aunque es sensible a mayúsculas y minúsculas, por mi propia elección). Y estoy bastante seguro de que CDATA es en realidad un elemento XML, no HTML.
Deji
2
Mi antiguo método (que describí aquí) era bastante ineficiente y recientemente comencé a reescribir muchos de los editores de contenido. Cuando se trata de hacer estas cosas, la posibilidad no es el problema; La mejor manera es siempre la principal preocupación. La respuesta real es "no hay una manera FÁCIL de hacerlo en PHP". NADIE dice que no hay forma de hacerlo en PHP o que es una idea terrible, pero que es imposible con la expresión regular, que honestamente nunca he intentado, pero el único defecto importante en mi respuesta es que asumí que la pregunta se refería a la expresión regular. dentro del contexto de PHP, que no es necesariamente el caso.
Deji
2

También probé con una expresión regular para esto. Es sobre todo útil para encontrar fragmentos de contenido emparejados con la siguiente etiqueta HTML, y no busca etiquetas cercanas coincidentes , pero recogerá etiquetas cercanas. Haga rodar una pila en su propio idioma para verificarlos.

Usar con las opciones 'sx'. 'g' también si te sientes con suerte:

(?P<content>.*?)                # Content up to next tag
(?P<markup>                     # Entire tag
  <!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
  <!--(?P<comment>.+?)-->|      # <!-- Comment -->
  </\s*(?P<close_tag>\w+)\s*>|  # </tag>
  <(?P<tag>\w+)                 # <tag ...
    (?P<attributes>
      (?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
        (?P<attribute_name>\w+)
        (?:\s*=\s*
          (?P<attribute_value>
            [\w:/.\-]+|         # Unquoted
            (?=(?P<_v>          # Quoted
              (?P<_q>['\"]).*?(?<!\\)(?P=_q)))
            (?P=_v)
          ))?
# </snip>
      )*
    )\s*
  (?P<is_self_closing>/?)   # Self-closing indicator
  >)                        # End of tag

Este está diseñado para Python (podría funcionar para otros lenguajes, no lo he probado, usa miradas positivas, miradas negativas y referencias posteriores con nombre). Apoya:

  • Abrir etiqueta - <div ...>
  • Cerrar etiqueta - </div>
  • Comentario <!-- ... -->
  • CDATA - <![CDATA[ ... ]]>
  • Etiqueta de cierre automático <div .../>
  • Valores de atributos opcionales: <input checked>
  • Valores de atributos sin comillas / comillas - <div style='...'>
  • Cotizaciones simples / dobles - <div style="...">
  • Citas escapadas: <a title='John\'s Story'>
    (esto no es HTML válido, pero soy un buen tipo)
  • Espacios alrededor de signos iguales <a href = '...'>
  • Capturas con nombre para bits interesantes

También es bastante bueno sobre no activar etiquetas mal formadas, como cuando se olvida una <o >.

Si su sabor regex admite capturas repetidas con nombre, entonces usted es dorado, pero Python reno (sé que regex sí, pero necesito usar Python vainilla). Esto es lo que obtienes:

  • content- Todo el contenido hasta la próxima etiqueta. Podrías dejar esto fuera.
  • markup - La etiqueta completa con todo lo que contiene.
  • comment - Si es un comentario, el contenido del comentario.
  • cdata- Si es un <![CDATA[...]]>, el contenido de CDATA.
  • close_tag- Si es una etiqueta cercana ( </div>), el nombre de la etiqueta.
  • tag- Si es una etiqueta abierta ( <div>), el nombre de la etiqueta.
  • attributes- Todos los atributos dentro de la etiqueta. Use esto para obtener todos los atributos si no obtiene grupos repetidos.
  • attribute - Repetido, cada atributo.
  • attribute_name - Repetido, cada nombre de atributo.
  • attribute_value- Repetido, cada valor de atributo. Esto incluye las comillas si fue citado.
  • is_self_closing- Esto es /si es una etiqueta de cierre automático, de lo contrario nada.
  • _qy _v- Ignorar estos; se usan internamente para referencias posteriores.

Si su motor regex no admite capturas repetidas con nombre, hay una sección llamada que puede usar para obtener cada atributo. Simplemente ejecute esa expresión regular en el attributesgrupo para obtener cada uno attribute, attribute_namey attribute_valuefuera de él.

Demostración aquí: https://regex101.com/r/mH8jSu/11

Hounshell
fuente
1

Las expresiones regulares no son lo suficientemente potentes para un lenguaje como HTML. Claro, hay algunos ejemplos en los que puedes usar expresiones regulares. Pero en general no es apropiado para el análisis.

Gumbo
fuente
0

Sabes ... hay mucha mentalidad de que NO PUEDES hacerlo y creo que todos en ambos lados de la cerca tienen razón y están equivocados. Usted PUEDE hacerlo, pero se necesita un poco más que un simple procesamiento de ejecutar una expresión regular en contra de ella. Tome esto (escribí esto dentro de una hora) como ejemplo. Asume que el HTML es completamente válido, pero dependiendo del idioma que esté utilizando para aplicar la expresión regular mencionada anteriormente, podría corregir el HTML para asegurarse de que tenga éxito. Por ejemplo, eliminar etiquetas de cierre que no deberían estar allí: </img>por ejemplo. Luego, agregue la barra diagonal de cierre HTML única a los elementos que les faltan, etc.

Lo usaría en el contexto de escribir una biblioteca que me permitiera realizar una recuperación de elementos HTML similar a la de JavaScript [x].getElementsByTagName(), por ejemplo. Simplemente uniría la funcionalidad que escribí en la sección DEFINE de la expresión regular y la usaría para entrar dentro de un árbol de elementos, uno a la vez.

Entonces, ¿será esta la respuesta final al 100% para validar HTML? No. Pero es un comienzo y con un poco más de trabajo, se puede hacer. Sin embargo, intentar hacerlo dentro de una ejecución de expresiones regulares no es práctico ni eficiente.

Erutan409
fuente