html - regulares - matches java ejemplo
Patrón de expresión regular que no coincide en ninguna parte de la cadena (8)
¡Oh, sí, puede usar expresiones regulares para analizar HTML!
Para la tarea que estás intentando, ¡las expresiones regulares están perfectamente bien!
Es cierto que la mayoría de las personas subestiman la dificultad de analizar HTML con expresiones regulares y, por lo tanto, lo hacen de forma deficiente.
Pero esta no es una falla fundamental relacionada con la teoría computacional. Esa tontería se repite mucho por aquí, pero no les creas.
Entonces, aunque ciertamente se puede hacer (este anuncio sirve como una prueba de existencia de este hecho incontrovertible), eso no significa que deba ser así.
Debes decidir por ti mismo si estás preparado para escribir lo que equivale a un analizador de HTML especial y dedicado de entre los regexes. La mayoría de las personas no lo son.
Pero yo soy. ☻
Soluciones generales de análisis HTML basadas en Regex
Primero mostraré lo fácil que es analizar HTML arbitrario con expresiones regulares. El programa completo está al final de esta publicación, pero el corazón del analizador es:
for (;;) {
given ($html) {
last when (pos || 0) >= length;
printf "/@%d=", (pos || 0);
print "doctype " when / /G (?&doctype) $RX_SUBS /xgc;
print "cdata " when / /G (?&cdata) $RX_SUBS /xgc;
print "xml " when / /G (?&xml) $RX_SUBS /xgc;
print "xhook " when / /G (?&xhook) $RX_SUBS /xgc;
print "script " when / /G (?&script) $RX_SUBS /xgc;
print "style " when / /G (?&style) $RX_SUBS /xgc;
print "comment " when / /G (?&comment) $RX_SUBS /xgc;
print "tag " when / /G (?&tag) $RX_SUBS /xgc;
print "untag " when / /G (?&untag) $RX_SUBS /xgc;
print "nasty " when / /G (?&nasty) $RX_SUBS /xgc;
print "text " when / /G (?&nontag) $RX_SUBS /xgc;
default {
die "UNCLASSIFIED: " .
substr($_, pos || 0, (length > 65) ? 65 : length);
}
}
}
¿Ves lo fácil que es leer?
Tal como está escrito, identifica cada pieza de HTML y dice dónde encontró esa pieza. Podrías modificarlo fácilmente para hacer lo que quieras con cualquier tipo de pieza dada, o para tipos más particulares que estos.
No tengo fallas en los casos de prueba (izquierda :): ejecuté con éxito este código en más de 100.000 archivos HTML, cada uno de los cuales pude obtener fácil y rápidamente. Más allá de eso, también lo he ejecutado en archivos específicamente diseñados para romper analizadores sintácticos.
Este no es un analizador ingenuo.
Oh, estoy seguro de que no es perfecto, pero no he logrado romperlo todavía. Me imagino que incluso si algo lo hiciera, la solución sería fácil de adaptar debido a la estructura clara del programa. Incluso los programas con expresiones regulares deben tener estructura.
Ahora que eso está fuera del camino, permítanme abordar la pregunta del OP.
Demostración de resolver la tarea del OP usando expresiones regulares
El pequeño programa html_input_rx
que html_input_rx
continuación produce el siguiente resultado, por lo que puede ver que analizar HTML con expresiones regulares funciona perfectamente para lo que desea hacer:
% html_input_rx Amazon.com-_Online_Shopping_for_Electronics,_Apparel,_Computers,_Books,_DVDs_/&_more.htm
input tag #1 at character 9955:
class => "searchSelect"
id => "twotabsearchtextbox"
name => "field-keywords"
size => "50"
style => "width:100%; background-color: #FFF;"
title => "Search for"
type => "text"
value => ""
input tag #2 at character 10335:
alt => "Go"
src => "http://g-ecx.images-amazon.com/images/G/01/x-locale/common/transparent-pixel._V192234675_.gif"
type => "image"
Etiquetas de entrada Parse, no ver entrada mal
Aquí está la fuente del programa que produjo el resultado anterior.
#!/usr/bin/env perl
#
# html_input_rx - pull out all <input> tags from (X)HTML src
# via simple regex processing
#
# Tom Christiansen <[email protected]>
# Sat Nov 20 10:17:31 MST 2010
#
################################################################
use 5.012;
use strict;
use autodie;
use warnings FATAL => "all";
use subs qw{
see_no_evil
parse_input_tags
input descape dequote
load_patterns
};
use open ":std",
IN => ":bytes",
OUT => ":utf8";
use Encode qw< encode decode >;
###########################################################
parse_input_tags
see_no_evil
input
###########################################################
until eof(); sub parse_input_tags {
my $_ = shift();
our($Input_Tag_Rx, $Pull_Attr_Rx);
my $count = 0;
while (/$Input_Tag_Rx/pig) {
my $input_tag = $+{TAG};
my $place = pos() - length ${^MATCH};
printf "input tag #%d at character %d:/n", ++$count, $place;
my %attr = ();
while ($input_tag =~ /$Pull_Attr_Rx/g) {
my ($name, $value) = @+{ qw< NAME VALUE > };
$value = dequote($value);
if (exists $attr{$name}) {
printf "Discarding dup attr value ''%s'' on %s attr/n",
$attr{$name} // "<undef>", $name;
}
$attr{$name} = $value;
}
for my $name (sort keys %attr) {
printf " %10s => ", $name;
my $value = descape $attr{$name};
my @Q; given ($value) {
@Q = qw[ " " ] when !/''/ && !/"/;
@Q = qw[ " " ] when /''/ && !/"/;
@Q = qw[ '' '' ] when !/''/ && /"/;
@Q = qw[ q( ) ] when /''/ && /"/;
default { die "NOTREACHED" }
}
say $Q[0], $value, $Q[1];
}
print "/n";
}
}
sub dequote {
my $_ = $_[0];
s{
(?<quote> ["''] )
(?<BODY>
(?s: (?! /k<quote> ) . ) *
)
/k<quote>
}{$+{BODY}}six;
return $_;
}
sub descape {
my $string = $_[0];
for my $_ ($string) {
s{
(?<! % )
% ( /p{Hex_Digit} {2} )
}{
chr hex $1;
}gsex;
s{
& /043
( [0-9]+ )
(?: ;
| (?= [^0-9] )
)
}{
chr $1;
}gsex;
s{
& /043 x
( /p{ASCII_HexDigit} + )
(?: ;
| (?= /P{ASCII_HexDigit} )
)
}{
chr hex $1;
}gsex;
}
return $string;
}
sub input {
our ($RX_SUBS, $Meta_Tag_Rx);
my $_ = do { local $/; <> };
my $encoding = "iso-8859-1"; # web default; wish we had the HTTP headers :(
while (/$Meta_Tag_Rx/gi) {
my $meta = $+{META};
next unless $meta =~ m{ $RX_SUBS
(?= http-equiv )
(?&name)
(?&equals)
(?= (?"e)? content-type )
(?&value)
}six;
next unless $meta =~ m{ $RX_SUBS
(?= content ) (?&name)
(?&equals)
(?<CONTENT> (?&value) )
}six;
next unless $+{CONTENT} =~ m{ $RX_SUBS
(?= charset ) (?&name)
(?&equals)
(?<CHARSET> (?&value) )
}six;
if (lc $encoding ne lc $+{CHARSET}) {
say "[RESETTING ENCODING $encoding => $+{CHARSET}]";
$encoding = $+{CHARSET};
}
}
return decode($encoding, $_);
}
sub see_no_evil {
my $_ = shift();
s{ <! DOCTYPE .*? > }{}sx;
s{ <! /[ CDATA /[ .*? /]/] > }{}gsx;
s{ <script> .*? </script> }{}gsix;
s{ <!-- .*? --> }{}gsx;
return $_;
}
sub load_patterns {
our $RX_SUBS = qr{ (?(DEFINE)
(?<nv_pair> (?&name) (?&equals) (?&value) )
(?<name> /b (?= /pL ) [/w/-] + (?<= /pL ) /b )
(?<equals> (?&might_white) = (?&might_white) )
(?<value> (?"ed_value) | (?&unquoted_value) )
(?<unwhite_chunk> (?: (?! > ) /S ) + )
(?<unquoted_value> [/w/-] * )
(?<might_white> /s * )
(?<quoted_value>
(?<quote> ["''] )
(?: (?! /k<quote> ) . ) *
/k<quote>
)
(?<start_tag> < (?&might_white) )
(?<end_tag>
(?&might_white)
(?: (?&html_end_tag)
| (?&xhtml_end_tag)
)
)
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
) }six;
our $Meta_Tag_Rx = qr{ $RX_SUBS
(?<META>
(?&start_tag) meta /b
(?:
(?&might_white) (?&nv_pair)
) +
(?&end_tag)
)
}six;
our $Pull_Attr_Rx = qr{ $RX_SUBS
(?<NAME> (?&name) )
(?&equals)
(?<VALUE> (?&value) )
}six;
our $Input_Tag_Rx = qr{ $RX_SUBS
(?<TAG> (?&input_tag) )
(?(DEFINE)
(?<input_tag>
(?&start_tag)
input
(?&might_white)
(?&attributes)
(?&might_white)
(?&end_tag)
)
(?<attributes>
(?:
(?&might_white)
(?&one_attribute)
) *
)
(?<one_attribute>
/b
(?&legal_attribute)
(?&might_white) = (?&might_white)
(?:
(?"ed_value)
| (?&unquoted_value)
)
)
(?<legal_attribute>
(?: (?&optional_attribute)
| (?&standard_attribute)
| (?&event_attribute)
# for LEGAL parse only, comment out next line
| (?&illegal_attribute)
)
)
(?<illegal_attribute> (?&name) )
(?<required_attribute> (?#no required attributes) )
(?<optional_attribute>
(?&permitted_attribute)
| (?&deprecated_attribute)
)
# NB: The white space in string literals
# below DOES NOT COUNT! It''s just
# there for legibility.
(?<permitted_attribute>
accept
| alt
| bottom
| check box
| checked
| disabled
| file
| hidden
| image
| max length
| middle
| name
| password
| radio
| read only
| reset
| right
| size
| src
| submit
| text
| top
| type
| value
)
(?<deprecated_attribute>
align
)
(?<standard_attribute>
access key
| class
| dir
| ltr
| id
| lang
| style
| tab index
| title
| xml:lang
)
(?<event_attribute>
on blur
| on change
| on click
| on dbl click
| on focus
| on mouse down
| on mouse move
| on mouse out
| on mouse over
| on mouse up
| on key down
| on key press
| on key up
| on select
)
)
}six;
}
UNITCHECK {
load_patterns();
}
END {
close(STDOUT)
|| die "can''t close stdout: $!";
}
¡Aquí tienes! ¡Nada para eso! :)
Solo usted puede juzgar si su habilidad con las expresiones regulares está a la altura de cualquier tarea de análisis en particular. El nivel de habilidad de cada persona es diferente, y cada nueva tarea es diferente. Para los trabajos en los que tiene un conjunto de entrada bien definido, las expresiones regulares son obviamente la elección correcta, porque es trivial juntar algunas cuando tiene que tratar un subconjunto restringido de HTML. Incluso los principiantes de expresiones regulares deben manejar esos trabajos con expresiones regulares. Cualquier otra cosa es exagerada.
Sin embargo , una vez que el código HTML comienza a reducirse, una vez que comienza a ramificarse de maneras que no puede predecir pero que son perfectamente legales, una vez que tiene que coincidir con más tipos de cosas o con dependencias más complejas, eventualmente llegará a un punto donde tienes que trabajar más duro para lograr una solución que use expresiones regulares de la que tendrías que usar una clase de análisis sintáctico. Donde ese punto de equilibrio cae depende nuevamente de su propio nivel de comodidad con las expresiones regulares.
¿Entonces qué debo hacer?
No voy a decirte lo que debes hacer o lo que no puedes hacer. Creo que eso está mal. Solo quiero presentarte posibilidades, abrir un poco los ojos. Puedes elegir lo que quieres hacer y cómo quieres hacerlo. No hay absolutos, y nadie más conoce tu propia situación tan bien como tú mismo. Si algo parece que es demasiado trabajo, bueno, tal vez lo sea. La programación debe ser divertida , ¿sabes? Si no es así, puede que lo estés haciendo mal.
Uno puede mirar mi programa html_input_rx
en cualquier cantidad de formas válidas. Uno de ellos es que puedes analizar HTML con expresiones regulares. Pero otra es que es mucho, mucho, mucho más difícil de lo que casi nadie piensa que es. Esto puede llevar fácilmente a la conclusión de que mi programa es un testimonio de lo que no debe hacer, porque realmente es demasiado difícil.
No estaré en desacuerdo con eso. Ciertamente, si todo lo que hago en mi programa no tiene sentido para usted después de un estudio, entonces no debería intentar usar expresiones regulares para este tipo de tarea. Para HTML específico, las expresiones regulares son geniales, pero para HTML genérico, son locura. Utilizo clases de análisis todo el tiempo, especialmente si es HTML que no he generado yo mismo.
Regexes óptimos para pequeños problemas de análisis de HTML, pésimo para los grandes
Incluso si mi programa se toma como una ilustración de por qué no se deben usar expresiones regulares para analizar HTML general, lo cual está bien, porque de alguna manera pretendía que fuera eso it, todavía debería ser una revelación para que más personas rompan lo terriblemente común y la desagradable y repugnante costumbre de escribir patrones ilegibles, no estructurados e inmanejables.
Los patrones no tienen que ser feos, y no tienen que ser difíciles. Si creas patrones desagradables, es un reflejo de ti, no de ellos.
Phenomenally Exquisite Regex Language
Me han pedido que señale que mi solución proferida a su problema ha sido escrita en Perl. ¿Estás sorprendido? ¿No te diste cuenta? ¿Es esta revelación una bomba?
Debo confesar que esta petición me resulta extraña en extremo, ya que cualquiera que no pueda entenderlo al mirar la primera línea de mi programa seguramente también tiene otras discapacidades mentales.
Es cierto que no todas las demás herramientas y lenguajes de programación son tan convenientes, expresivos y poderosos en lo que respecta a las expresiones regulares como lo es Perl. Existe un gran espectro, y algunos son más adecuados que otros. En general, los lenguajes que expresan expresiones regulares como parte del lenguaje central en lugar de como una biblioteca son más fáciles de usar. No he hecho nada con las expresiones regulares que no podría hacer en, digamos, PCRE, aunque estructuraría el programa de manera diferente si estuviera usando C.
Finalmente, otros idiomas se pondrán al día con Perl ahora en términos de expresiones regulares. Digo esto porque cuando Perl comenzó, nadie más tenía nada como las expresiones regulares de Perl. Di lo que quieras, pero aquí es donde Perl claramente ganó: todos copiaron las expresiones regulares de Perl aunque en diferentes etapas de su desarrollo. Perl fue pionero casi (no del todo, pero casi) de todo lo que ha llegado a confiar hoy en los patrones modernos, sin importar la herramienta o el lenguaje que use. Entonces eventualmente los otros se pondrán al corriente.
Pero solo alcanzarán a Perl en el pasado, tal como es ahora. Todo avanza En regexes, nada más, hacia donde conduce Perl, otros siguen. ¿Dónde estará Perl una vez que todos los demás finalmente se den cuenta de dónde está Perl ahora? No tengo idea, pero sé que nosotros también nos habremos movido. Probablemente estaremos más cerca del estilo de patrones de elaboración de Perl₆ .
Si te gusta ese tipo de cosas pero te gustaría usarlo en Perl₅, es posible que te interese el maravilloso módulo Regexp :: Grammars de Damian Conway . Es completamente asombroso, y hace que lo que he hecho aquí en mi programa parezca tan primitivo como el mío hace los patrones que las personas agrupan sin espacios en blanco o identificadores alfabéticos. ¡Echale un vistazo!
Simple HTML Chunker
Aquí está la fuente completa del analizador que mostré desde el comienzo de esta publicación.
No estoy sugiriendo que deba usar esto en una clase de análisis rigurosamente probada. Pero estoy cansado de las personas que fingen que nadie puede analizar HTML con expresiones regulares simplemente porque no pueden. Claramente puede, y este programa es una prueba de esa afirmación.
Claro, no es fácil, ¡pero es posible!
Y tratar de hacerlo es una terrible pérdida de tiempo, porque existen buenas clases de análisis sintáctico que debes usar para esta tarea. La respuesta correcta para las personas que intentan analizar HTML arbitrario no es que sea imposible. Esa es una respuesta fácil y falsa. La respuesta correcta y honesta es que no deberían intentarlo porque es demasiado molesto descubrirlo desde cero; no deberían romperse la espalda tratando de recuperar una rueda que funciona perfectamente bien.
Por otro lado, HTML que cae dentro de un subconjunto predecible es ultra fácil de analizar con expresiones regulares. No es de extrañar que las personas intenten usarlos, ya que para problemas pequeños, problemas de juguetes quizás, nada podría ser más fácil. Por eso es tan importante distinguir las dos tareas, específicas frente a genéricas, ya que no exigen necesariamente el mismo enfoque.
Espero en el futuro aquí ver un tratamiento más justo y honesto de las preguntas sobre HTML y expresiones regulares.
Aquí está mi HTML lexer. No intenta hacer un análisis de validación; solo identifica los elementos léxicos. Podrías pensar en esto más como un chunker de HTML que como un analizador de HTML. No es muy indulgente con HTML roto, aunque hace algunas concesiones muy pequeñas en esa dirección.
Incluso si nunca analiza el HTML completo usted mismo (y ¿por qué debería hacerlo? ¡Es un problema resuelto!), Este programa tiene muchos bits genéricos geniales que creo que mucha gente puede aprender mucho. ¡Disfrutar!
#!/usr/bin/env perl
#
# chunk_HTML - a regex-based HTML chunker
#
# Tom Christiansen <[email protected]
# Sun Nov 21 19:16:02 MST 2010
########################################
use 5.012;
use strict;
use autodie;
use warnings qw< FATAL all >;
use open qw< IN :bytes OUT :utf8 :std >;
MAIN: {
$| = 1;
lex_html(my $page = slurpy());
exit();
}
########################################################################
sub lex_html {
our $RX_SUBS; ###############
my $html = shift(); # Am I... #
for (;;) { # forgiven? :)#
given ($html) { ###############
last when (pos || 0) >= length;
printf "/@%d=", (pos || 0);
print "doctype " when / /G (?&doctype) $RX_SUBS /xgc;
print "cdata " when / /G (?&cdata) $RX_SUBS /xgc;
print "xml " when / /G (?&xml) $RX_SUBS /xgc;
print "xhook " when / /G (?&xhook) $RX_SUBS /xgc;
print "script " when / /G (?&script) $RX_SUBS /xgc;
print "style " when / /G (?&style) $RX_SUBS /xgc;
print "comment " when / /G (?&comment) $RX_SUBS /xgc;
print "tag " when / /G (?&tag) $RX_SUBS /xgc;
print "untag " when / /G (?&untag) $RX_SUBS /xgc;
print "nasty " when / /G (?&nasty) $RX_SUBS /xgc;
print "text " when / /G (?&nontag) $RX_SUBS /xgc;
default {
die "UNCLASSIFIED: " .
substr($_, pos || 0, (length > 65) ? 65 : length);
}
}
}
say ".";
}
#####################
# Return correctly decoded contents of next complete
# file slurped in from the <ARGV> stream.
#
sub slurpy {
our ($RX_SUBS, $Meta_Tag_Rx);
my $_ = do { local $/; <ARGV> }; # read all input
return unless length;
use Encode qw< decode >;
my $bom = "";
given ($_) {
$bom = "UTF-32LE" when / ^ /xFf /xFe /0 /0 /x; # LE
$bom = "UTF-32BE" when / ^ /0 /0 /xFe /xFf /x; # BE
$bom = "UTF-16LE" when / ^ /xFf /xFe /x; # le
$bom = "UTF-16BE" when / ^ /xFe /xFf /x; # be
$bom = "UTF-8" when / ^ /xEF /xBB /xBF /x; # st00pid
}
if ($bom) {
say "[BOM $bom]";
s/^...// if $bom eq "UTF-8"; # st00pid
# Must use UTF-(16|32) w/o -[BL]E to strip BOM.
$bom =~ s/-[LB]E//;
return decode($bom, $_);
# if BOM found, don''t fall through to look
# for embedded encoding spec
}
# Latin1 is web default if not otherwise specified.
# No way to do this correctly if it was overridden
# in the HTTP header, since we assume stream contains
# HTML only, not also the HTTP header.
my $encoding = "iso-8859-1";
while (/ (?&xml) $RX_SUBS /pgx) {
my $xml = ${^MATCH};
next unless $xml =~ m{ $RX_SUBS
(?= encoding ) (?&name)
(?&equals)
(?"e) ?
(?<ENCODING> (?&value) )
}sx;
if (lc $encoding ne lc $+{ENCODING}) {
say "[XML ENCODING $encoding => $+{ENCODING}]";
$encoding = $+{ENCODING};
}
}
while (/$Meta_Tag_Rx/gi) {
my $meta = $+{META};
next unless $meta =~ m{ $RX_SUBS
(?= http-equiv ) (?&name)
(?&equals)
(?= (?"e)? content-type )
(?&value)
}six;
next unless $meta =~ m{ $RX_SUBS
(?= content ) (?&name)
(?&equals)
(?<CONTENT> (?&value) )
}six;
next unless $+{CONTENT} =~ m{ $RX_SUBS
(?= charset ) (?&name)
(?&equals)
(?<CHARSET> (?&value) )
}six;
if (lc $encoding ne lc $+{CHARSET}) {
say "[HTTP-EQUIV ENCODING $encoding => $+{CHARSET}]";
$encoding = $+{CHARSET};
}
}
return decode($encoding, $_);
}
########################################################################
# Make sure to this function is called
# as soon as source unit has been compiled.
UNITCHECK { load_rxsubs() }
# useful regex subroutines for HTML parsing
sub load_rxsubs {
our $RX_SUBS = qr{
(?(DEFINE)
(?<WS> /s * )
(?<any_nv_pair> (?&name) (?&equals) (?&value) )
(?<name> /b (?= /pL ) [/w:/-] + /b )
(?<equals> (?&WS) = (?&WS) )
(?<value> (?"ed_value) | (?&unquoted_value) )
(?<unwhite_chunk> (?: (?! > ) /S ) + )
(?<unquoted_value> [/w:/-] * )
(?<any_quote> ["''] )
(?<quoted_value>
(?<quote> (?&any_quote) )
(?: (?! /k<quote> ) . ) *
/k<quote>
)
(?<start_tag> < (?&WS) )
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
(?<end_tag>
(?&WS)
(?: (?&html_end_tag)
| (?&xhtml_end_tag) )
)
(?<tag>
(?&start_tag)
(?&name)
(?:
(?&WS)
(?&any_nv_pair)
) *
(?&end_tag)
)
(?<untag> </ (?&name) > )
# starts like a tag, but has screwed up quotes inside it
(?<nasty>
(?&start_tag)
(?&name)
.*?
(?&end_tag)
)
(?<nontag> [^<] + )
(?<string> (?"ed_value) )
(?<word> (?&name) )
(?<doctype>
<!DOCTYPE
# please don''t feed me nonHTML
### (?&WS) HTML
[^>]* >
)
(?<cdata> <!/[CDATA/[ .*? /]/] > )
(?<script> (?= <script ) (?&tag) .*? </script> )
(?<style> (?= <style ) (?&tag) .*? </style> )
(?<comment> <!-- .*? --> )
(?<xml>
< /? xml
(?:
(?&WS)
(?&any_nv_pair)
) *
(?&WS)
/? >
)
(?<xhook> < /? .*? /? > )
)
}six;
our $Meta_Tag_Rx = qr{ $RX_SUBS
(?<META>
(?&start_tag) meta /b
(?:
(?&WS) (?&any_nv_pair)
) +
(?&end_tag)
)
}six;
}
# nobody *ever* remembers to do this!
END { close STDOUT }
Estoy intentando hacer corresponder <input>
campos <input>
type "hidden" con este patrón:
/<input type="hidden" name="([^"]*?)" value="([^"]*?)" />/
Esto es información de formulario de muestra:
<input type="hidden" name="SaveRequired" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input type="hidden" name="__VIEWSTATE3" value="ZVVV91yjY" /><input type="hidden" name="__VIEWSTATE0" value="3" /><input type="hidden" name="__VIEWSTATE" value="" /><input type="hidden" name="__VIEWSTATE" value="" />
Pero no estoy seguro de que los atributos de type
, name
y value
siempre aparezcan en el mismo orden. Si el atributo de type
es el último, la coincidencia fallará porque en mi patrón está al principio.
Pregunta:
¿Cómo puedo cambiar mi patrón para que coincida independientemente de las posiciones de los atributos en la etiqueta <input>
?
PD: por cierto, estoy usando la herramienta de escritorio RegEx basada en Adobe Air para probar expresiones regulares.
- Puedes escribir una novela como lo hizo Tchrist
- Puede usar una biblioteca DOM, cargar el HTML y usar xpath y simplemente usar
//input[@type="hidden"]
. O si no desea usar xpath, simplemente obtenga todas las entradas y filtre cuáles están ocultas congetAttribute
.
Prefiero # 2.
<?php
$d = new DOMDocument();
$d->loadHTML(
''
<p>fsdjl</p>
<form><div>fdsjl</div></form>
<input type="hidden" name="blah" value="hide yo kids">
<input type="text" name="blah" value="hide yo kids">
<input type="hidden" name="blah" value="hide yo wife">
'');
$x = new DOMXpath($d);
$inputs = $x->evaluate(''//input[@type="hidden"]'');
foreach ( $inputs as $input ) {
echo $input->getAttribute(''value''), ''<br>'';
}
Resultado:
hide yo kids<br>hide yo wife<br>
Contrario a todas las respuestas aquí, por lo que estás tratando de hacer, regex es una solución perfectamente válida. Esto se debe a que NO estás tratando de hacer coincidir las etiquetas equilibradas. ¡ESO sería imposible con Regex! Pero solo estás haciendo coincidir lo que está en una etiqueta, y eso es perfectamente regular.
Este es el problema, sin embargo. No puede hacerlo con solo una expresión regular ... necesita hacer una coincidencia para capturar una etiqueta <input>
, luego realice un procesamiento adicional sobre eso. Tenga en cuenta que esto solo funcionará si ninguno de los valores de los atributos tiene un carácter >
en ellos, por lo que no es perfecto, pero debería ser suficiente para las entradas sanas.
Aquí hay un código de Perl (pseudo) para mostrarle lo que quiero decir:
my $html = readLargeInputFile();
my @input_tags = $html =~ m/
(
<input # Starts with "<input"
(?=[^>]*?type="hidden") # Use lookahead to make sure that type="hidden"
[^>]+ # Grab the rest of the tag...
//> # ...except for the />, which is grabbed here
)/xgm;
# Now each member of @input_tags is something like <input type="hidden" name="SaveRequired" value="False" />
foreach my $input_tag (@input_tags)
{
my $hash_ref = {};
# Now extract each of the fields one at a time.
($hash_ref->{"name"}) = $input_tag =~ /name="([^"]*)"/;
($hash_ref->{"value"}) = $input_tag =~ /value="([^"]*)"/;
# Put $hash_ref in a list or something, or otherwise process it
}
El principio básico aquí es, no intentes hacer demasiado con una expresión regular. Como ha notado, las expresiones regulares imponen una cierta cantidad de orden. Entonces, lo que tienes que hacer es, en primer lugar, hacer coincidir el CONTEXTO de lo que estás tratando de extraer, luego hacer subcomprobación en los datos que desees.
EDITAR: Sin embargo, estaré de acuerdo en que, en general, usar un analizador HTML es probablemente más fácil y mejor, y realmente debería considerar rediseñar su código o volver a examinar sus objetivos. :-) Pero tuve que publicar esta respuesta como un contador a la reacción instintiva de que analizar cualquier subconjunto de HTML es imposible: HTML y XML son irregulares cuando se considera la especificación completa, pero la especificación de una etiqueta es decentemente regular. , ciertamente dentro del poder de PCRE.
En el espíritu de la solución Lexer de Tom Christiansen, aquí hay un enlace al artículo aparentemente olvidado de Robert Cameron de 1998, REX: XML Shallow Parsing with Regular Expressions.
http://www.cs.sfu.ca/~cameron/REX.html
Abstracto
La sintaxis de XML es lo suficientemente simple como para poder analizar un documento XML en una lista de sus elementos de marcado y texto con una sola expresión regular. Un análisis tan superficial de un documento XML puede ser muy útil para la construcción de una variedad de herramientas livianas de procesamiento XML. Sin embargo, las expresiones regulares complejas pueden ser difíciles de construir e incluso más difíciles de leer. Utilizando una forma de programación alfabetizada para expresiones regulares, este documento documenta un conjunto de expresiones de análisis sintáctico XML que pueden usarse como base para un análisis sintáctico de XML simple, correcto, eficiente, robusto e independiente del lenguaje. También se proporcionan implementaciones completas de analizador superficial de menos de 50 líneas cada una en Perl, JavaScript y Lex / Flex.
Si le gusta leer sobre expresiones regulares, el trabajo de Cameron es fascinante. Su escritura es concisa, completa y muy detallada. No solo le muestra cómo construir la expresión regular REX, sino también un enfoque para construir cualquier expresión regular compleja a partir de partes más pequeñas.
He estado usando la expresión regular de REX de manera intermitente durante 10 años para resolver el tipo de problema que el cartel inicial preguntaba (¿cómo puedo asociar esta etiqueta en particular pero no con otra etiqueta muy similar?). He descubierto que la expresión regular que desarrolló es completamente confiable.
REX es particularmente útil cuando se enfoca en detalles léxicos de un documento; por ejemplo, cuando transforma un tipo de documento de texto (por ejemplo, texto plano, XML, SGML, HTML) en otro, donde el documento puede no ser válido, bien formado, o incluso parseable durante la mayor parte de la transformación. Le permite marcar islas de marcado en cualquier lugar dentro de un documento sin perturbar el resto del documento.
Si bien me encantan los contenidos del resto de estas respuestas, en realidad no respondieron la pregunta directamente o de manera correcta. Incluso la respuesta de Platinum fue demasiado complicada y también menos eficiente. Entonces me forzaron a poner esto.
Soy un gran defensor de Regex, cuando se usa correctamente. Pero debido al estigma (y el rendimiento), siempre afirmo que el XML o HTML bien formado debe usar un Analizador XML. E incluso un mejor rendimiento sería el análisis de cadenas, aunque hay una línea entre la legibilidad si eso se pone demasiado fuera de control. Sin embargo, esa no es la pregunta. La pregunta es cómo hacer coincidir una etiqueta de entrada de tipo oculto. La respuesta es:
<input[^>]*type="hidden"[^>]*>
Dependiendo de tu sabor, la única opción de expresiones regulares que necesitarías incluir es la opción de ignorar el caso.
I would like to use **DOMDocument**
to extract the html code.
$dom = new DOMDocument();
$dom ->loadHTML($input);
$x = new DOMXpath($dom );
$results = $x->evaluate(''//input[@type="hidden"]'');
foreach ( $results as $item) {
print_r( $item->getAttribute(''value'') );
}
BTW, you can test it in here - regex101.com. It shows the result at real time. Some rules about Regexp: http://www.eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html Reader .
suppose your html content is stored in string html then in order to get every input that contain type hidden you can use regular expression
var regex = /(<input.*?type/s?=/s?["'']hidden["''].*?>)/g;
html.match(regex);
the above regex find <input
followed by any number of characters until it gets type="hidden"
or type=''hidden'' followed by any number of characters till it gets >
/g tell regular expression to find every substring that matches to the given pattern.
you can try this :
<[A-Za-z ="/_0-9+]*>
and for closer result you can try this :
<[ ]*input[ ]+type="hidden"[ ]*name=[A-Za-z ="_0-9+]*[ ]*[/]*>
you can test your regex pattern here http://regexpal.com/
these pattens are good for this:
<input type="hidden" name="SaveRequired" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input type="hidden" name="__VIEWSTATE3" value="ZVVV91yjY" />
and for random order of type
, name
and value
u can use this :
<[ ]*input[ ]*[A-Za-z ="_0-9+/]*>
o
<[ ]*input[ ]*[A-Za-z ="_0-9+/]*[ ]*[/]>
on this :
<input name="SaveRequired" type="hidden" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input name="__VIEWSTATE3" type="hidden" value="ZVVV91yjY" />
`
by the way i think you want something like this :
<[ ]*input(([ ]*type="hidden"[ ]*name=[A-Za-z0-9_+"]*[ ]*value=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*type="hidden"[ ]*value=[A-Za-z0-9_+"]*[ ]*name=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*name=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*value=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*value=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*name=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*name=[A-Za-z0-9_+"]*[ ]*value=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*)+)[ ]*/>|<[ ]*input(([ ]*value=[A-Za-z0-9_+"]*[ ]*name=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*)+)[ ]*/>
its not good but it works in any way.
test it in : http://regexpal.com/