tester regular html regex perl

regular - Regex para que coincida con todas las etiquetas HTML, excepto<p> y</ p>



perl regular expression g modifier (13)

Necesito unir y eliminar todas las etiquetas usando una expresión regular en Perl. Tengo lo siguiente:

<//??(?!p).+?>

Pero esto todavía coincide con la etiqueta de cierre </p> . ¿Alguna pista sobre cómo hacer coincidir con la etiqueta de cierre también?

Tenga en cuenta que esto se está realizando en xhtml.


Dado que HTML no es un idioma normal

HTML no lo es, pero las etiquetas HTML son y pueden describirse adecuadamente mediante expresiones regulares.


Como el HTML no es un lenguaje normal, no esperaría que una expresión regular hiciera un muy buen trabajo al combinarlo. Podrían estar a la altura de esta tarea (aunque no estoy convencido), pero consideraría buscar en otro lado; Estoy seguro de que Perl debe tener algunas bibliotecas listas para usar para manipular HTML.

De todos modos, creo que lo que quieres unir es </? (P. + |. *) (/ S *. *)> No codicioso (no conozco los caprichos de la sintaxis de expresiones regulares de perl, así que no puedo ayudar promover). Estoy asumiendo que eso significa espacio en blanco. Tal vez no. De cualquier manera, desea algo que combine los atributos con el espacio en blanco del nombre de la etiqueta. Pero es más difícil que eso, ya que las personas a menudo colocan corchetes angulares sin escotaduras dentro de los guiones y comentarios, y tal vez incluso los valores de los atributos citados, con los que no desea coincidir.

Entonces, como digo, realmente no creo que las expresiones regulares sean la herramienta adecuada para el trabajo.


En mi opinión, intentar analizar HTML con algo que no sea un analizador HTML es solo pedir un mundo de dolor. HTML es un lenguaje realmente complejo (que es una de las principales razones por las que se creó XHTML, que es mucho más simple que HTML).

Por ejemplo, esto:

<HTML / <HEAD / <TITLE / > / <P / >

es un documento HTML completo, 100% bien formado y 100% válido. (Bueno, falta la declaración DOCTYPE, pero aparte de eso ...)

Es semánticamente equivalente a

<html> <head> <title> &gt; </title> </head> <body> <p> &gt; </p> </body> </html>

Pero es un HTML válido con el que tendrás que lidiar. Podrías, por supuesto, idear una expresión regular para analizarlo, pero, como otros ya sugirieron, usar un analizador de HTML real es mucho más fácil.


La expresión original se puede hacer funcionar con muy poco esfuerzo:

<(?>/?)(?!p).+?>

El problema fue que el /? (o /?) abandonó lo que coincidía cuando la afirmación después de que falló. Al usar un grupo que no realiza rastreos (?> ...) a su alrededor, se cuida de que nunca suelte la barra coincidente, por lo que la afirmación (?! P) siempre está anclada al comienzo del texto de la etiqueta.

(Dicho esto, estoy de acuerdo en que, en general, analizar HTML con expresiones regulares no es el camino a seguir).


No estoy seguro de por qué quieres hacer esto: regex para la desinfección de HTML no siempre es el mejor método (debes recordar desinfectar los atributos y demás, eliminar javascript: hrefs y los que te gustan) ... pero una expresión regular que coincida con HTML etiquetas que no son <p></p> :

(<[^pP].*?>|</[^pP]>)

Verboso:

( < # < opening tag [^pP].*? # p non-p character, then non-greedy anything > # > closing tag | # ....or.... </ # </ [^pP] # a non-p tag > # > )


Probablemente también deberías eliminar los atributos en la etiqueta <p>, ya que alguien malo podría hacer algo como:

<p onclick="document.location.href=''http://www.evil.com''">Clickable text</p>

La forma más sencilla de hacerlo es utilizar las expresiones regulares que la gente sugiere aquí para buscar etiquetas & ltp> con atributos y reemplazarlas por etiquetas <p> sin atributos. Sólo para estar en el lado seguro.


Prueba esto, debería funcionar:

/<//?([^p](/s.+?)?|..+?)>/

Explicación: coincide con una sola letra excepto "p", seguida de un espacio en blanco opcional y más caracteres, o varias letras (al menos dos).

/ EDITAR: he agregado la capacidad de manejar atributos en etiquetas p .


Se me ocurrió esto:

<(?!//?p(?=>|/s.*>))//?.*?> x/ < # Match open angle bracket (?! # Negative lookahead (Not matching and not consuming) //? # 0 or 1 / p # p (?= # Positive lookahead (Matching and not consuming) > # > - No attributes | # or /s # whitespace .* # anything up to > # close angle brackets - with attributes ) # close positive lookahead ) # close negative lookahead # if we have got this far then we don''t match # a p tag or closing p tag # with or without attributes //? # optional close tag symbol (/) .*? # and anything up to > # first closing tag /

Esto ahora se ocupará de las etiquetas p con o sin atributos y las etiquetas p de cierre, pero coincidirá con etiquetas pre y similares, con o sin atributos.

No elimina los atributos, pero mis datos de origen no los ponen. Puedo cambiar esto más tarde para hacer esto, pero esto será suficiente por ahora.


Si insiste en usar una expresión regular, algo como esto funcionará en la mayoría de los casos:

# Remove all HTML except "p" tags $html =~ s{<(?>/?)(?:[^pP]|[pP][^/s>/])[^>]*>}{}g;

Explicación:

s{ < # opening angled bracket (?>/?) # ratchet past optional / (?: [^pP] # non-p tag | # ...or... [pP][^/s>/] # longer tag that begins with p (e.g., <pre>) ) [^>]* # everything until closing angled bracket > # closing angled bracket }{}gx; # replace with nothing, globally

Pero realmente, ahórrese algunos dolores de cabeza y use un analizador en su lugar. CPAN tiene varios módulos que son adecuados. Aquí hay un ejemplo que usa el módulo HTML::TokeParser que viene con la extremadamente capaz distribución HTML::Parser CPAN:

use strict; use HTML::TokeParser; my $parser = HTML::TokeParser->new(''/some/file.html'') or die "Could not open /some/file.html - $!"; while(my $t = $parser->get_token) { # Skip start or end tags that are not "p" tags next if(($t->[0] eq ''S'' || $t->[0] eq ''E'') && lc $t->[1] ne ''p''); # Print everything else normally (see HTML::TokeParser docs for explanation) if($t->[0] eq ''T'') { print $t->[1]; } else { print $t->[-1]; } }

HTML::Parser acepta la entrada en forma de un nombre de archivo, un manejador de archivo abierto o una cadena. Envolver el código anterior en una biblioteca y hacer que el destino sea configurable (es decir, no solo print como en el ejemplo anterior) no es difícil. El resultado será mucho más confiable, mantenible y posiblemente también más rápido (HTML :: Parser usa un backend basado en C) que tratar de usar expresiones regulares.


Suponiendo que esto funcionará en PERL como lo hace en los idiomas que afirman usar sintaxis compatible con PERL:

/<//?[^p][^>]*>/

EDITAR:

Pero eso no coincidirá con una etiqueta <pre> o <param> , desafortunadamente.

Esto, tal vez?

/<//?(?!p>|p )[^>]+>/

Eso debería cubrir las etiquetas <p> que tienen atributos, también.


También es posible que desee permitir espacios en blanco antes de la "p" en la etiqueta p. No estoy seguro de la frecuencia con la que se encontrará con esto, pero <p> es un HTML perfectamente válido.


Usé Xetius regex y funciona bien. Excepto algunas etiquetas generadas por flex que pueden ser:
sin espacios dentro Traté de arreglarlo con un simple ? after / s y parece que está funcionando:

<(?!//?p(?=>|/s?.*>))//?.*?>

Lo estoy usando para eliminar etiquetas del texto html generado en flex, así que también agregué más etiquetas exceptuadas:

<(?!//?(p|a|b|i|u|br)(?=>|/s?.*>))//?.*?>


Xetius, resucitando esta antigua pregunta porque tenía una solución simple que no se mencionaba. (Encontró su pregunta mientras hacía una investigación para una búsqueda de recompensa de expresiones regulares ).

Con todos los descargos de responsabilidad sobre el uso de expresiones regulares para analizar html, aquí hay una manera simple de hacerlo.

#!/usr/bin/perl $regex = ''(<//?p[^>]*>)|<[^>]*>''; $subject = ''Bad html <a> </I> <p>My paragraph</p> <i>Italics</i> <p class="blue">second</p>''; ($replaced = $subject) =~ s/$regex/$1/eg; print $replaced . "/n";

Vea esta demostración en vivo

Referencia

Cómo hacer coincidir el patrón, excepto en las situaciones s1, s2, s3

Cómo hacer coincidir un patrón a menos que ...