it-swarm.com.de

Was ist zu tun? Das Muster für reguläre Ausdrücke stimmt in keiner Zeichenfolge überein.

Ich versuche, <input>-Typ "ausgeblendete" Felder anhand dieses Musters zu finden:

/<input type="hidden" name="([^"]*?)" value="([^"]*?)" />/

Dies ist ein Beispielformulardaten:

<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="" />

Ich bin jedoch nicht sicher, dass die Attribute type, name und value immer in derselben Reihenfolge angezeigt werden. Wenn das type-Attribut das letzte ist, schlägt die Übereinstimmung fehl, da sie in meinem Muster am Anfang steht.

Frage:
Wie kann ich mein Muster ändern, damit es unabhängig von den Positionen der Attribute im <input>-Tag passt?

P.S .: Übrigens benutze ich Adobe Air based RegEx Desktop Tool zum Testen regulärer Ausdrücke.

169
Salman

Im Gegensatz zu allen Antworten hier ist Reg24 das, was Sie versuchen, Regex zu tun, eine absolut gültige Lösung. Das liegt daran, dass Sie NICHT versuchen, ausgeglichene Tags abzugleichen - DAS wäre mit Regex unmöglich! Sie stimmen jedoch nur mit dem überein, was in einem Tag enthalten ist, und das ist absolut normal.

Hier ist jedoch das Problem. Sie können es nicht mit nur einem regulären Ausdruck tun ... Sie müssen einen Treffer machen, um ein <input>-Tag zu erfassen, und dann das weiter bearbeiten. Beachten Sie, dass dies nur funktioniert, wenn keiner der Attributwerte ein >-Zeichen enthält. Das ist also nicht perfekt, sollte aber für sinnvolle Eingaben ausreichen.

Hier ist ein Perl (Pseudo) -Code, um zu zeigen, was ich meine:

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
}

Das Grundprinzip hier ist, versuchen Sie nicht, mit einem regulären Ausdruck zu viel zu tun. Wie Sie bemerkt haben, erzwingen reguläre Ausdrücke eine gewisse Reihenfolge. Stattdessen müssen Sie zunächst den CONTEXT der zu extrahierenden Daten abgleichen und dann die gewünschten Daten submatchen.

BEARBEITEN: Ich stimme jedoch zu, dass die Verwendung eines HTML-Parsers im Allgemeinen wahrscheinlich einfacher und besser ist, und Sie sollten in Erwägung ziehen, Ihren Code umzugestalten oder Ihre Ziele zu überprüfen. :-) Aber ich musste diese Antwort als Antwort auf die knifflige Reaktion veröffentlichen, dass das Analysieren von HTML-Teilmengen nicht möglich ist: HTML und XML sind beide unregelmäßig, wenn Sie die gesamte Spezifikation berücksichtigen sicherlich in der Macht von PCRE.

105
Platinum Azure

Oh ja, Sie können Regexes zum Analysieren von HTML verwenden!

Für die Aufgabe, die Sie versuchen, sind reguläre Ausdrücke vollkommen in Ordnung!

Es ist ist wahr, dass die meisten Leute die Schwierigkeit, HTML mit regulären Ausdrücken zu analysieren, unterschätzen und dies daher nur schlecht tun.

Dies ist jedoch kein grundlegender Fehler in Bezug auf die Computertheorie. Diese Dummheit wird hier viel herumgescherzt, aber glauben Sie ihnen nicht.

Dies ist zwar durchaus möglich (dieses Posting dient als Existenzbeweis für diese unbestreitbare Tatsache), bedeutet jedoch nicht, dass dies sollte sein soll.

Sie müssen selbst entscheiden, ob Sie in der Lage sind, einen speziellen HTML-Parser aus regulären Ausdrücken zu erstellen. Die meisten Leute sind nicht.

Aber I bin. ☻


Allgemeine Regex-basierte HTML-Parsing-Lösungen

Zuerst zeige ich, wie einfach es ist, beliebig HTML mit regulären Ausdrücken zu analysieren. Das vollständige Programm finden Sie am Ende dieses Beitrags. Das Herzstück des Parsers ist jedoch:

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);
    }
  }
}

Sehen Sie, wie easy das zu lesen ist?

Wie geschrieben, identifiziert es jedes Stück HTML und gibt an, wo es dieses Stück gefunden hat. Sie können es leicht modifizieren, um mit einer bestimmten Art von Stück oder für spezifischere Arten als diese zu tun, was auch immer Sie wollen.

Ich habe keine fehlgeschlagenen Testfälle (links): Ich habe diesen Code mit mehr als 100.000 HTML-Dateien erfolgreich ausgeführt - jede einzelne konnte ich schnell und einfach in die Hände bekommen. Darüber hinaus starte ich es auch für Dateien spezifisch konstruiert , um naive Parser zu unterbrechen.

Dies ist nicht ein naiver Parser.

Oh, ich bin mir sicher, dass es nicht perfekt ist, aber ich habe es noch nicht geschafft, es zu brechen. Ich gehe davon aus, dass die Korrektur aufgrund der klaren Struktur des Programms selbst dann problemlos durchgeführt werden kann, wenn dies der Fall ist. Sogar regexlastige Programme sollten strukturiert sein.

Lassen Sie mich die Frage des OP beantworten, da dies nicht möglich ist.

Demo zur Lösung der OP-Aufgabe mit Regexen

Das kleine Programm html_input_rx, das ich unten aufführe, erzeugt die folgende Ausgabe, sodass Sie sehen können, dass das Parsen von HTML mit regulären Ausdrücken für das, was Sie tun möchten, gut funktioniert:

% 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"

Eingabemarken analysieren, siehe Keine bösen Eingaben

Hier ist die Quelle für das Programm, mit dem die obige Ausgabe erstellt wurde.

#!/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) 
            (?= (?&quote)? 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>           (?&quoted_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) 
                (?:
                    (?&quoted_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: $!";
} 

Es geht los! Nichts dabei! :)

Nur you kann beurteilen, ob Ihre Fähigkeit mit Regexen einer bestimmten Parsing-Aufgabe gewachsen ist. Jeder hat ein anderes Können und jede neue Aufgabe ist anders. Für Jobs, bei denen Sie eine genau definierte Eingabemenge haben, sind reguläre Ausdrücke offensichtlich die richtige Wahl, da es trivial ist, einige zusammenzustellen, wenn Sie eine eingeschränkte Teilmenge von HTML-Code haben, mit dem Sie sich befassen müssen. Sogar Regex-Anfänger sollten diese Jobs mit Regex behandeln. Alles andere ist übertrieben.

Allerdings, sobald der HTML-Code weniger genau ist, sobald er sich in einer Weise verzweigt, die Sie nicht vorhersagen können, die aber vollkommen legal sind, sobald Sie mehr verschiedene Arten von Dingen oder komplexeren Abhängigkeiten zuordnen müssen. Sie werden irgendwann einen Punkt erreichen, an dem Sie härter arbeiten müssen, um eine Lösung zu erzielen, die reguläre Ausdrücke verwendet, als wenn Sie eine Analyseklasse verwenden müssten. Wo diese Gewinnschwelle liegt, hängt wiederum von Ihrem eigenen Komfortniveau mit Regex ab.

Also was soll ich tun?

Ich werde Ihnen nicht sagen, was Sie müssen tun oder was Sie können nicht tun. Ich denke, das ist falsch. Ich möchte Ihnen nur die Möglichkeiten vorstellen, Ihre Augen ein wenig öffnen. Sie können wählen, was Sie tun möchten und wie Sie es tun möchten. Es gibt keine absoluten Zahlen - und niemand kennt Ihre eigene Situation so gut wie Sie. Wenn etwas so aussieht, als ob es zu viel Arbeit wäre, ist es es vielleicht. Die Programmierung sollte fun sein, wissen Sie. Wenn dies nicht der Fall ist, machen Sie es möglicherweise falsch.

Man kann mein Programm html_input_rx auf eine beliebige Anzahl gültiger Arten betrachten. Eine davon ist, dass Sie in der Tat kann HTML mit regulären Ausdrücken analysieren. Aber eine andere ist, dass es viel, viel schwieriger ist, als fast jeder denkt, dass es so ist. Dies kann leicht zu dem Schluss führen, dass mein Programm ein Testament für das ist, was Sie tun sollten nicht , weil es wirklich zu schwer ist.

Dem werde ich nicht widersprechen. Wenn Ihnen nach dem Studium alles, was ich in meinem Programm tue, keinen Sinn macht, sollten Sie nicht versuchen, Regex für diese Art von Aufgabe zu verwenden. Regexes sind für spezifisches HTML großartig, aber für generisches HTML sind sie gleichbedeutend mit Wahnsinn. Ich verwende die ganze Zeit Parsing-Klassen, insbesondere wenn es sich um HTML handelt, das ich nicht selbst generiert habe.

Regexes optimal für small HTML-Analyseprobleme, pessimal für große

Auch wenn mein Programm als Beispiel dafür dient, warum Sie nicht ​​Regexes zum Parsen von allgemeinem HTML verwenden sollten - was in Ordnung ist, weil ich es irgendwie so gemeint habe ☺ -, sollte es dennoch ein Augenöffner sein So brechen immer mehr Menschen die schrecklich häufige und unangenehme Angewohnheit, unlesbare, unstrukturierte und nicht zu pflegende Muster zu schreiben.

Muster müssen nicht hässlich sein, und sie müssen nicht hart sein. Wenn Sie hässliche Muster erstellen, ist dies eine Reflexion auf Sie, nicht auf sie.

Phänomenal exquisite Regex-Sprache

Ich wurde gebeten, darauf hinzuweisen, dass meine ausführliche Lösung für Ihr Problem in Perl geschrieben wurde. Bist du überrascht? Hast du es nicht bemerkt? Ist diese Offenbarung eine Bombe?

Ich muss gestehen, dass ich diese Bitte im Extremfall bizarr finde, da jeder, der das nicht aus der ersten Zeile meines Programms herausfinden kann, sicherlich andere geistige Behinderungen hat als Gut.

Es ist richtig, dass nicht alle anderen Tools und Programmiersprachen in Bezug auf Regexes so praktisch, ausdrucksstark und leistungsstark sind wie Perl. Es gibt ein großes Spektrum, von denen einige geeigneter sind als andere. Im Allgemeinen ist es einfacher, mit Sprachen zu arbeiten, die reguläre Ausdrücke als Teil der Kernsprache und nicht als Bibliothek ausgedrückt haben. Ich habe nichts mit regulären Ausdrücken gemacht, die Sie beispielsweise in PCRE nicht hätten tun können, obwohl Sie das Programm anders strukturieren würden, wenn Sie C verwenden würden.

Irgendwann werden andere Sprachen mit Perl in Bezug auf die regulären Ausdrücke mithalten können. Ich sage das, weil damals, als Perl anfing, niemand etwas Ähnliches wie Perls Regexes hatte. Sagen Sie, was Sie wollen, aber hier hat Perl eindeutig gewonnen: Alle haben die regulären Ausdrücke von Perl kopiert, wenn auch in unterschiedlichen Stadien ihrer Entwicklung. Perl leistete Pionierarbeit für fast (nicht alle, aber fast) alles, worauf Sie sich heute in modernen Mustern verlassen, unabhängig davon, welches Tool oder welche Sprache Sie verwenden. Also werden die anderen irgendwann aufholen.

Aber sie werden nur nachholen, wo Perl früher war, so wie es jetzt ist. Alles schreitet voran. In regulären Ausdrücken folgen andere, wenn nichts anderes, wohin Perl führt. Wo wird Perl sein, wenn alle anderen endlich wissen, wo Perl jetzt ist? Ich habe keine Ahnung, aber ich weiß, dass auch wir umgezogen sind. Wahrscheinlich sind wir näher bei Perls Handwerksmusterstil .

Wenn Ihnen so etwas gefällt, Sie es aber gerne in Perl₅ verwenden möchten, könnte das Modul Damian Conways wundervoll Regexp :: Grammatiken für Sie von Interesse sein. Es ist absolut fantastisch und lässt das, was ich hier in meinem Programm getan habe, genauso primitiv erscheinen, wie meine Muster, die Menschen ohne Leerzeichen oder alphabetische Bezeichner zusammenfügen. Hör zu!


Einfacher HTML-Chunker

Hier ist die vollständige Quelle für den Parser, von dem ich das Herzstück zu Beginn dieses Beitrags gezeigt habe.

Ich schlage nicht vor, dass Sie dies über eine streng getestete Analyseklasse verwenden sollten. Aber ich habe es satt, vorzugeben, dass niemand HTML mit regulären Ausdrücken parsen kann, nur weil sie nicht können. Das können Sie ganz klar, und dieses Programm ist ein Beweis für diese Behauptung.

Sicher ist es nicht einfach, aber es ist möglich!

Dies zu versuchen ist eine schreckliche Zeitverschwendung, da es gute Analyseklassen gibt, die Sie sollten für diese Aufgabe verwenden. Die richtige Antwort für Leute, die versuchen, willkürlich HTML zu analysieren, ist nicht ​​dass es unmöglich ist. Das ist eine einfache und unaufrichtige Antwort. Die richtige und ehrliche Antwort ist, dass sie es nicht versuchen sollten, weil es zu mühsam ist, es von Grund auf neu herauszufinden. Sie sollten sich nicht den Rücken brechen und danach streben, ein Rad neu zu erfinden, das perfekt funktioniert.

Auf der anderen Seite lässt sich HTML, das innerhalb einer vorhersagbaren Teilmenge liegt, sehr einfach mit regulären Ausdrücken analysieren. Es ist kein Wunder, dass die Leute versuchen, sie zu benutzen, denn bei kleinen Problemen, vielleicht bei Spielzeugproblemen, könnte nichts einfacher sein. Aus diesem Grund ist es so wichtig, die beiden Aufgaben - spezifisch und generisch - zu unterscheiden, da diese nicht unbedingt denselben Ansatz erfordern.

Ich hoffe, dass wir in Zukunft fairer und ehrlicher mit Fragen zu HTML und regulären Ausdrücken umgehen können.

Hier ist mein HTML-Lexer. Es wird nicht versucht, eine Überprüfung durchzuführen. es identifiziert nur die lexikalischen Elemente. Sie können sich das eher als einen HTML-Chunker als als einen HTML-Parser vorstellen. Es ist nicht sehr nachsichtig für kaputtes HTML, obwohl es einige sehr kleine Toleranzen in diese Richtung zulässt.

Auch wenn Sie niemals selbst komplettes HTML analysieren (und warum sollten Sie das tun? Es ist ein gelöstes Problem!), Enthält dieses Programm viele coole Regex-Bits, von denen meines Erachtens viele Menschen viel lernen können. Genießen!

#!/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)
                            (?&quote) ?
            (?<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)
            (?= (?&quote)? 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>           (?&quoted_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> (?&quoted_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 }
671
tchrist
  1. Sie können einen Roman schreiben, wie er es getan hat
  2. Sie können eine DOM-Bibliothek verwenden, den HTML-Code laden und xpath verwenden und einfach //input[@type="hidden"] verwenden. Wenn Sie xpath nicht verwenden möchten, rufen Sie einfach alle Eingaben ab und filtern Sie, welche mit getAttribute ausgeblendet sind.

Ich bevorzuge # 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>';
}

Ergebnis:

hide yo kids<br>hide yo wife<br>
122
meder omuraliev

Im Sinne der Lexer-Lösung von Tom Christiansen finden Sie hier einen Link zu Robert Camerons scheinbar vergessenem Artikel von 1998: REX: XML Shallow Parsing mit regulären Ausdrücken.

http://www.cs.sfu.ca/~cameron/REX.html

Abstrakt

Die Syntax von XML ist so einfach, dass es möglich ist, ein XML-Dokument mit einem einzigen regulären Ausdruck in eine Liste seiner Markup- und Textelemente zu parsen. Eine solche flache Analyse eines XML-Dokuments kann für die Erstellung einer Reihe von XML-Verarbeitungswerkzeugen mit geringem Gewicht sehr nützlich sein. Komplexe reguläre Ausdrücke können jedoch schwierig zu konstruieren und noch schwieriger zu lesen sein. Dieses Dokument dokumentiert eine Form der geschulten Programmierung für reguläre Ausdrücke und dokumentiert einen Satz flacher XML-Ausdrucksausdrücke, die als Grundlage für einfaches, korrektes, effizientes, robustes und sprachunabhängiges flaches XML-Parsing dienen können. Vollständige Implementierungen des flachen Parsers mit jeweils weniger als 50 Zeilen in Perl, JavaScript und Lex/Flex werden ebenfalls angegeben.

Wenn Sie gerne über reguläre Ausdrücke lesen, ist Camerons Artikel faszinierend. Sein Schreiben ist knapp, gründlich und sehr detailliert. Er zeigt Ihnen nicht nur, wie Sie den regulären Ausdruck von REX erstellen, sondern auch einen Ansatz, um komplexe Regex aus kleineren Teilen aufzubauen.

Ich habe den regulären Ausdruck von REX seit 10 Jahren ein- und ausgeschaltet, um das Problem zu lösen, nach dem das ursprüngliche Poster gefragt wurde (wie stelle ich diesen Tag dar, aber nicht einen anderen sehr ähnlichen Tag?). Ich habe festgestellt, dass der von ihm entwickelte Regex absolut zuverlässig ist.

REX ist besonders nützlich, wenn Sie sich auf lexikalische Details eines Dokuments konzentrieren, z. B. wenn Sie eine Art Textdokument (z. B. Nur-Text, XML, SGML, HTML) in ein anderes konvertieren, bei dem das Dokument möglicherweise nicht gültig ist. gut geformt oder sogar für den Großteil der Transformation analysierbar. Damit können Sie Markup-Inseln an beliebiger Stelle innerhalb eines Dokuments anvisieren, ohne den Rest des Dokuments zu stören.

20
David

Obwohl ich den Inhalt der restlichen Antworten sehr schätze, haben sie die Frage nicht direkt oder als richtig beantwortet. Selbst die Antwort von Platinum war zu kompliziert und auch weniger effizient. Also musste ich das sagen.

Ich bin ein großer Befürworter von Regex, wenn er richtig eingesetzt wird. Aufgrund von Stigmatisierung (und Leistung) gebe ich jedoch immer an, dass wohlgeformtes XML oder HTML einen XML-Parser verwenden sollte. Eine noch bessere Leistung wäre das String-Parsing, obwohl zwischen Lesbarkeit und Lesbarkeit zu unterscheiden ist, wenn dies zu kurz kommt. Das ist jedoch nicht die Frage. Die Frage ist, wie ein verstecktes Eingabetag abgeglichen werden soll. Die Antwort ist:

<input[^>]*type="hidden"[^>]*>

Abhängig von Ihrem Geschmack ist die einzige Option, die Sie einschließen müssen, die Option ignorecase.

5
Suamere

sie können dies versuchen:

<[A-Za-z ="/_0-9+]*>

und für ein genaueres Ergebnis können Sie folgendes versuchen:

<[ ]*input[ ]+type="hidden"[ ]*name=[A-Za-z ="_0-9+]*[ ]*[/]*>

sie können Ihr Regex-Muster hier testen. http://regexpal.com/

diese Muster sind dafür gut:

<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" />

und für die zufällige Reihenfolge von type können name und value u verwendet werden:

<[ ]*input[ ]*[A-Za-z ="_0-9+/]*>

oder

<[ ]*input[ ]*[A-Za-z ="_0-9+/]*[ ]*[/]>

dazu:

<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" />

`

Übrigens denke ich, dass Sie so etwas wollen:

<[ ]*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"[ ]*)+)[ ]*/>

es ist nicht gut, aber es funktioniert in irgendeiner Weise.

testen Sie es in: http://regexpal.com/

2

Ich möchte **DOMDocument** verwenden, um den HTML-Code zu extrahieren.

$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') );
}

Übrigens, Sie können es hier testen - regex101.com. Es zeigt das Ergebnis in Echtzeit. Einige Regeln zu Regexp: http://www.Eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.htmlLeser .

1
HTML5 developer

angenommen, Ihr HTML-Inhalt wird in der Zeichenfolge "html" gespeichert. Um jede Eingabe zu erhalten, die den Typ versteckt enthält, können Sie reguläre Ausdrücke verwenden

var regex = /(<input.*?type\s?=\s?["']hidden["'].*?>)/g;
html.match(regex);

der obige reguläre Ausdruck findet <input, gefolgt von einer beliebigen Anzahl von Zeichen, bis er type="hidden" erhält oder type = 'hidden', gefolgt von einer beliebigen Anzahl von Zeichen, bis er > abruft.

/ g teilt dem regulären Ausdruck mit, alle Teilzeichenfolgen zu finden, die dem angegebenen Muster entsprechen.

0
Nitin9791