Wzór wyrażenia regularnego nie pasujący nigdzie w łańcuchu

Próbuję dopasować <input> wpisz "ukryte" pola używając tego wzorca:

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

Oto przykładowe dane formularza:

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

Ale nie jestem pewien, czy type, name, i value atrybuty będą zawsze wyświetlane w tej samej kolejności. Jeśli atrybut type jest ostatni, mecz się nie powiedzie, ponieważ w moim wzorze jest na początku.

Pytanie:
Jak Mogę zmienić mój wzorzec tak, aby pasował niezależnie od pozycji atrybutów w <input> tag?

P. S.: przy okazji używam Adobe Air na podstawie RegEx Desktop Tool do testowania wyrażeń regularnych.

Author: Salman, 2010-11-20

8 answers

W przeciwieństwie do wszystkich odpowiedzi tutaj, dla tego, co próbujesz zrobić regex jest całkowicie poprawne rozwiązanie. To dlatego, że nie próbujesz dopasować zrównoważonych tagów - to byłoby niemożliwe z regex! Ale pasujesz tylko do tego, co jest w jednym znaczniku, a to jest całkowicie normalne.

Ale w tym problem. Nie możesz tego zrobić za pomocą tylko jednego wyrażenia regularnego... aby przechwycić znacznik <input>, musisz wykonać jedno dopasowanie, a następnie wykonać dalsze przetwarzanie. Zauważ, że będzie to działać tylko wtedy, gdy żaden z atrybutów wartości mają w sobie znak >, więc nie jest idealny, ale powinien wystarczyć dla zdrowych wejść.

Oto jakiś Perl (pseudo)kod, który pokaże ci co mam na myśli:

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
}

Podstawową zasadą jest tutaj, nie próbuj robić zbyt wiele za pomocą jednego wyrażenia regularnego. Jak zauważyłeś, wyrażenia regularne wymuszają pewną kolejność. Zamiast tego musisz najpierw dopasować kontekst tego, co próbujesz wyodrębnić, a następnie poddawać dane chcę.

EDIT: zgadzam się jednak, że ogólnie rzecz biorąc, używanie parsera HTML jest prawdopodobnie łatwiejsze i lepsze i naprawdę powinieneś rozważyć przeprojektowanie kodu lub ponowne zbadanie swoich celów. :- ) Ale musiałem opublikować tę odpowiedź jako przeciwstawienie do reakcji kolanowej, że parsowanie dowolnego podzbioru HTML jest niemożliwe: HTML i XML są zarówno nieregularne, jeśli wziąć pod uwagę całą specyfikację, ale specyfikacja tagu jest przyzwoicie regularna, na pewno w mocy PCRE.

 100
Author: Platinum Azure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-08 14:59:53

Oh Yes You Can Use Regexes to Parse HTML!

Dla zadania, które próbujesz, wyrażenia regularne są doskonale!

To to prawda, że większość ludzi nie docenia trudności parsowania HTML za pomocą wyrażeń regularnych i dlatego robi to słabo.

Ale nie jest to jakaś zasadnicza wada związana z teorią obliczeniową. Ta głupota jest tu często wypaczana, ale nie wierz im.

Więc choć na pewno można zrobić (ten wpis służy jako dowód istnienia tego niepodważalnego faktu), to nie znaczy, że powinien be.

Musisz sam zdecydować, czy jesteś w stanie napisać, co oznacza dedykowany, specjalny parser HTML z wyrażeń regularnych. Większość ludzi nie.

Aleja jestem. ☻


Ogólne rozwiązania do parsowania HTML oparte na Regex

Najpierw pokażę jak łatwo jest parsować dowolny HTML z wyrażeniami regularnymi. Pełny program znajduje się na końcu tego posta, ale sercem parsera jest:

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

Widzisz jak to jest czytać?

Jak napisano, identyfikuje każdy kawałek HTML i mówi, gdzie znalazł ten kawałek. Możesz łatwo zmodyfikować go tak, aby robił cokolwiek chcesz z dowolnym typem utworu, lub dla bardziej konkretnych typów niż te.

Nie mam nieudanych przypadków testowych (po lewej:): udało mi się uruchomić ten kod na ponad 100 000 plikach HTML - każdy z nich mogłem szybko i łatwo dostać w swoje ręce. Poza tym uruchomiłem go również na plikach specjalnie skonstruowanych , aby złamać naiwne parsery.

To jesta nie naiwny parser.

Oh, jestem pewien, że nie jest idealny, ale nie udało mi się go jeszcze złamać. Pomyślałem, że nawet gdyby coś się stało, poprawka byłaby łatwa do dopasowania ze względu na przejrzystą strukturę programu. Nawet programy regex-heavy powinny mieć stucture.

Teraz, gdy to jest z pozwól, że odpowiem na pytanie.

Demo rozwiązania zadania OP za pomocą wyrażeń regularnych

Mały html_input_rx program, który załączam poniżej, wytwarza następujące wyjście, dzięki czemu możesz zobaczyć, że parsowanie HTML z wyrażeniami regularnymi działa dobrze dla tego, co chcesz zrobić:

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

Parse Input Tags, See No Evil Input

Oto źródło dla programu, który wyprodukował dane wyjściowe powyżej.

#!/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: $!";
} 

Proszę bardzo! Nic do tego! :)

Tylko ty może ocenić, czy twoje umiejętności z wyrażeniami regularnymi są odpowiednie do konkretnego zadania parsowania. Każdy poziom umiejętności jest inny, a każde nowe zadanie jest inne. W przypadku zadań, w których masz dobrze zdefiniowany zestaw wejściowy, wyrażenia regularne są oczywiście właściwym wyborem, ponieważ jest trywialne złożenie niektórych razem, gdy masz ograniczony podzbiór HTML do czynienia z. Nawet początkujący regex powinni obsługiwać te zadania z regexami. Wszystko inne to przesada.

Jednakże , raz HTML zaczyna się coraz mniej przybity, gdy zaczyna ramify w sposób nie można przewidzieć, ale które są całkowicie legalne, gdy trzeba dopasować więcej różnych rodzajów rzeczy lub z bardziej złożonych zależności, będzie w końcu osiągnąć punkt, w którym trzeba pracować ciężej, aby osiągnąć rozwiązanie, które używa wyrażeń regularnych niż trzeba byłoby użyć klasy parsowania. Gdzie ten punkt progu rentowności spada ponownie zależy od własnego poziomu komfortu z wyrażeniami regularnymi.

Więc Co Powinienem Zrobić?

Nie powiem ci, co musisz zrobić, a czego nie możesz. Myślę, że to złe. Chcę Ci tylko przedstawić możliwości, otworzyć oczy. Możesz wybrać, co chcesz zrobić i jak chcesz to zrobić. Nie ma absolutów - i nikt inny nie zna Twojej sytuacji tak dobrze, jak ty sam. Jeśli coś wydaje się za dużo pracy, to może tak jest. Programowanie powinno być zabawa, wiesz. Jeśli nie, możesz być robi to źle.

MoĹźna patrzeÄ ‡ na mój program html_input_rx na dowolnÄ ... iloĹ " Ä ‡ waĺźnych sposobĂłw. Jednym z nich jest to, że rzeczywiście można parsować HTML za pomocą wyrażeń regularnych. Ale innym jest to, że jest znacznie, znacznie, znacznie trudniejsze niż prawie każdy kiedykolwiek myśli, że jest. Może to łatwo prowadzić do wniosku, że mój program jest świadectwem tego, czego nie powinieneś robić, ponieważ jest to naprawdę zbyt trudne.

Nie będę się z tym nie zgadzał. Na pewno jeśli wszystko co robię w moim programie nie czyni sens dla ciebie po pewnym badaniu, to nie należy próbować używać wyrażeń regularnych dla tego rodzaju zadań. Dla konkretnego HTML, wyrażenia regularne są świetne, ale dla ogólnego HTML, są równoznaczne z szaleństwem. Używam klas parsujących cały czas, zwłaszcza jeśli jest to HTML, którego sam nie wygenerowałem.

Regexy optymalne dla małych problemów z parsowaniem HTML, pesymistyczne dla dużych

Nawet jeśli mój program jest brany jako ilustracja dlaczego powinieneś a nie używać wyrażeń regularnych do parsowania ogólny HTML - co jest OK, bo trochę chciałem, aby to było to, że ☺ - to nadal powinien być otwieracz do oczu, więc więcej ludzi łamie strasznie powszechny i paskudny, paskudny nawyk pisania nieczytelnych, niestrukturalnych i niemożliwych do utrzymania wzorców.

Wzory nie muszą być brzydkie i nie muszą być trudne. Jeśli tworzysz brzydkie wzory, jest to odbicie na Tobie, nie na nich.

Fenomenalnie Znakomity Język Regex

Zostałem poproszony o zwrócenie uwagi na to, że mój profer rozwiązanie twojego problemu zostało napisane w Perlu. Jesteś zaskoczony? Nie zauważyłeś? Czy to objawienie to sensacja?

Muszę przyznać, że uważam tę prośbę za dziwną w skrajności, ponieważ każdy, kto nie może tego rozgryźć patrząc na pierwszą linię mojego programu, z pewnością ma również inne upośledzenia umysłowe.

Prawdą jest, że nie wszystkie inne narzędzia i języki programowania są tak wygodne, ekspresyjne i potężne, jeśli chodzi o wyrażenia regularne, jak Perl jest. Istnieje duże spektrum, niektóre są bardziej odpowiednie niż inne. Ogólnie rzecz biorąc, języki, które wyrażały wyrażenia regularne jako część języka podstawowego, a nie jako biblioteka, są łatwiejsze do pracy. Nie zrobiłem nic z wyrażeniami regularnymi, czego nie można zrobić w, powiedzmy, PCRE, chociaż inaczej skonstruowałbyś program, gdybyś używał C.

W końcu inne języki będą nadrabiać zaległości w Perlu pod względem wyrażeń regularnych. Mówię to, bo kiedy Perl na początku nikt inny nie miał nic takiego jak wyrażenia regularne Perla. Mów co chcesz, ale to tutaj Perl wyraźnie wygrał: wszyscy kopiowali wyrażenia regularne Perla, chociaż na różnych etapach ich rozwoju. Perl był pionierem prawie (nie wszystkiego, ale prawie) wszystkiego, na czym dzisiaj polegasz we współczesnych wzorcach, bez względu na to, jakiego narzędzia lub języka używasz. Więc w końcu inninadgonią .

Ale nadrobią tylko to, gdzie kiedyś był Perl, tak jak jest teraz. Wszystko idzie naprzód. W wyrażeniach regularnych, jeśli nic innego, gdzie prowadzi Perl, inne podążają za nim. Gdzie będzie Perl, gdy wszyscy w końcu dojdą do tego, gdzie jest teraz Perl? Nie mam pojęcia, ale wiem, że my też się przeprowadzimy. Prawdopodobnie będziemy bliżej stylu Perla CRA tworzenia wzorów.

Jeśli lubisz tego typu rzeczy, ale chciałbyś używać ich w Perl₅, możesz być zainteresowany Damian Conway ' s wonderful Regexp::Grammars module. On całkowicie niesamowite, i sprawia, że to, co zrobiłem tutaj w moim programie, wydaje się tak prymitywne jak mój, sprawia, że wzory, które ludzie pakują razem bez białych znaków lub alfabetycznych identyfikatorów. Zobacz!


Simple HTML Chunker

Oto pełne źródło parsera, które pokazałem na początku tego postu.

Jestem nie sugeruję, że powinieneś użyć tego nad rygorystycznie testowaną klasą parsowania. Ale mam dość ludzi. udawanie, że nikt nie może parsować HTML z wyrażeniami regularnymi tylko dlatego, że One nie mogą. najwyraźniej Możesz, a ten program jest dowodem tego twierdzenia.

Jasne, że nie jest to łatwe, ale tojest możliwe!

I próba zrobienia tego jest straszną stratą czasu, ponieważ istnieją dobre klasy parsujące, które powinieneś użyć do tego zadania. Właściwą odpowiedzią dla osób próbujących przeanalizować dowolny HTML jest , a nie , że jest to niemożliwe. To proste. i nieszczera odpowiedź. Prawidłowa i szczera odpowiedź jest taka, że nie powinni tego próbować, ponieważ jest to zbyt kłopotliwe, aby dowiedzieć się od zera; nie powinni łamać pleców dążąc do reïnvent koła, które działa doskonale.

Z drugiej strony, HTML, który mieści się w przewidywalnym podzbiorze , jest niezwykle łatwy do przetworzenia za pomocą wyrażeń regularnych. Nic dziwnego, że ludzie próbują ich używać, ponieważ w przypadku małych problemów, być może problemów z zabawkami, nic nie może być łatwiejsze. Dlatego jest tak ważne jest rozróżnienie dwóch zadań-specyficznych i ogólnych-ponieważ niekoniecznie wymagają one tego samego podejścia.

Mam nadzieję, że w przyszłości tutaj, aby zobaczyć bardziej sprawiedliwe i uczciwe traktowanie pytań o HTML i wyrażenia regularne.

Oto mój lexer HTML. Nie próbuje przeprowadzić walidacji; po prostu identyfikuje elementy leksykalne. Możesz myśleć o tym bardziej jako o HTML chunkerze niż o HTML parserze. Nie jest bardzo wyrozumiały dla zepsutego HTML, chociaż sprawia, że niektóre bardzo małe dodatki w tym kierunku.

Nawet jeśli nigdy sam nie parsujesz pełnego HTML (i dlaczego powinieneś? to rozwiązany problem!), ten program ma wiele fajnych bitów regex, które wierzę, że wiele osób może się wiele nauczyć. Smacznego!

#!/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 }
 659
Author: tchrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 21:02:31
    Możesz napisać powieść jak tchrist]}
  1. możesz użyć biblioteki DOM, załadować HTML i użyć xpath i po prostu użyć //input[@type="hidden"]. Lub jeśli nie chcesz używać xpath, po prostu Pobieraj wszystkie wejścia i filtruj, które są ukryte za pomocą getAttribute.

Wolę #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>';
}

Wynik:

hide yo kids<br>hide yo wife<br>
 120
Author: meder omuraliev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-20 19:43:21

W duchu rozwiązania lexera Toma Christiansena, oto link do pozornie zapomnianego artykułu Roberta Camerona z 1998 roku, REX: XML płytkie parsowanie wyrażeniami regularnymi.

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

Streszczenie

Składnia XML jest na tyle prosta, że można przetworzyć dokument XML do listy jego znaczników i elementów tekstowych za pomocą jednego wyrażenia regularnego. Taki płytki parse dokumentu XML może być bardzo przydatne do budowy różnych lekkich narzędzi do przetwarzania XML. Jednak złożone wyrażenia regularne mogą być trudne do skonstruowania i jeszcze trudniejsze do odczytania. Korzystając z formy Literackiego programowania wyrażeń regularnych, dokument ten dokumentuje zestaw wyrażeń XML shallow parsing, które mogą być używane jako podstawa do prostego, poprawnego, wydajnego, solidnego i niezależnego od języka XML shallow parsing. Kompletne implementacje parserów o długości poniżej 50 linii każda w Perlu, JavaScript podano również Lex / Flex.

Jeśli lubisz czytać o wyrażeniach regularnych, praca Camerona jest fascynująca. Jego pismo jest zwięzłe, dokładne i bardzo szczegółowe. Pokazuje on nie tylko, jak konstruować Wyrażenie regularne REX, ale także podejście do tworzenia złożonych wyrażeń regularnych z mniejszych części.

Używam wyrażenia regularnego REX od 10 lat, aby rozwiązać problem, o który pytał początkowy plakat (jak dopasować ten konkretny tag ale nie jakiś inny bardzo podobny tag?). Uważam, że regex, który opracował, jest całkowicie wiarygodny.

REX jest szczególnie przydatny, gdy skupiasz się na szczegółach leksykalnych dokumentu-na przykład podczas przekształcania jednego rodzaju dokumentu tekstowego (np. zwykły tekst, XML, SGML, HTML) w inny, gdzie dokument może nie być poprawny, dobrze uformowany lub nawet przetwarzalny przez większość transformacji. Pozwala na kierowanie Wysp znaczników w dowolnym miejscu dokumentu bez zakłócania reszty dokumentu.

 19
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-20 02:59:35

Chociaż uwielbiam treść pozostałych odpowiedzi, nie odpowiedziały one tak naprawdę bezpośrednio lub tak poprawnie. Nawet odpowiedź Platinum była zbyt skomplikowana, a także mniej skuteczna. Więc musiałem to umieścić.

Jestem wielkim zwolennikiem Regex, gdy jest używany poprawnie. Ale ze względu na piętno (i wydajność) zawsze stwierdzam, że dobrze uformowany XML lub HTML powinien używać parsera XML. A jeszcze lepszą wydajnością byłoby parsowanie strun, choć jest granica między czytelność, jeśli to wymknie się spod kontroli. Jednak to nie jest pytanie. Pytanie brzmi, jak dopasować Ukryty znacznik wejściowy. Odpowiedź brzmi:

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

W zależności od smaku, jedyną opcją wyrażeń regularnych, którą musisz uwzględnić, jest opcja ignorecase.

 4
Author: Suamere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-18 21:26:36

Możesz spróbować tego:

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

I dla bliższego wyniku możesz spróbować tego:

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

Możesz przetestować swój wzór regex tutaj http://regexpal.com/

Te patteny są do tego dobre:

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

I dla losowej kolejności type , name i value u można użyć tego:

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

Lub

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

`

Swoją drogą myślę, że chcesz coś takiego:

<[ ]*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 to działa w jakikolwiek sposób.

Przetestuj w: http://regexpal.com/

 1
Author: Shamshirsaz.Navid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-31 21:33:34

Chciałbym użyć **DOMDocument** do wyodrębnienia kodu html.

$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, możesz to przetestować tutaj - regex101.com. pokazuje wynik w czasie rzeczywistym. Niektóre zasady dotyczące wyrażenia regularnego: http://www.eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html czytelnik .

 1
Author: HTML5 developer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-11 06:30:40

Załóżmy, że twoja zawartość html jest przechowywana w łańcuchu html, wtedy aby uzyskać wszystkie dane wejściowe zawierające ukryty typ, możesz użyć wyrażenia regularnego

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

Powyższy regex find <input po którym następuje dowolna liczba znaków, dopóki nie otrzyma type="hidden" lub type='hidden', po którym następuje dowolna liczba znaków, dopóki nie otrzyma >

/g każe wyrażeniu regularnemu znaleźć każdy podłańcuch pasujący do podanego wzorca.

 0
Author: Nitin9791,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-13 14:36:18