web-dev-qa-db-fra.com

Que faire Le modèle d'expression régulière ne correspond nulle part dans la chaîne?

J'essaie de faire correspondre les champs "cachés" de type <input> en utilisant ce modèle:

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

Voici des exemples de données de formulaire:

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

Mais je ne suis pas sûr que les attributs type, name et value apparaîtront toujours dans le même ordre. Si l’attribut type vient en dernier, la correspondance échouera car dans mon modèle, c’est au début.

Question:
Comment puis-je modifier mon modèle afin qu'il corresponde quelles que soient les positions des attributs dans la balise <input>?

P.S .: En passant, j'utilise le Adobe Air based RegEx Desktop Tool pour tester les expressions régulières.

169
Salman

Contrairement à toutes les réponses fournies ici, regex est une solution tout à fait valable. C'est parce que vous n'essayez PAS de faire correspondre les balises équilibrées - CELA serait impossible avec regex! Mais vous ne faites correspondre que ce qui est dans une balise, et c'est parfaitement normal.

Voici le problème, cependant. Vous ne pouvez pas le faire avec une seule expression rationnelle ... vous devez faire une correspondance pour capturer une balise <input>, puis effectuer un traitement supplémentaire à ce sujet. Notez que cela ne fonctionnera que si aucune des valeurs d'attribut ne contient un caractère >, ce n'est donc pas parfait, mais cela devrait suffire pour des entrées saines.

Voici un code (pseudo) Perl pour vous montrer ce que je veux dire:

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
}

Le principe de base est le suivant: n'essayez pas de faire trop avec une seule expression régulière. Comme vous l'avez remarqué, les expressions régulières imposent un certain ordre. Donc, ce que vous devez faire à la place est d’abord de faire correspondre le CONTEXTE de ce que vous essayez d’extraire, puis de faire une correspondance avec les données que vous voulez.

MODIFIER: Cependant, je conviens que, d’une manière générale, l’utilisation d’un analyseur HTML est probablement plus simple et plus efficace et que vous devriez vraiment envisager de redéfinir votre code ou de réexaminer vos objectifs. :-) Mais je devais poster cette réponse pour contrer la réaction irréfléchie voulant qu’analyser n’importe quel sous-ensemble de HTML soit impossible: HTML et XML sont tous les deux irréguliers si l’on considère la spécification complète, mais la spécification d’une balise est assez régulière , certainement à la portée de PCRE.

105
Platinum Azure

Oh oui, vous pouvez utiliser les expressions rationnelles pour analyser le code HTML!

Pour la tâche que vous tentez, les expressions rationnelles sont parfaitement bien!

Il est vrai que la plupart des gens sous-estiment la difficulté de l'analyse HTML avec des expressions régulières et le font donc très mal.

Mais ce n’est pas un défaut fondamental lié à la théorie informatique. Cette sottise est souvent évoquée ici, mais n’y croyez pas.

Donc, bien que cela puisse être fait (cette publication sert de preuve de l'existence de ce fait incontestable), cela ne veut pas dire que devrait be.

Vous devez décider vous-même si vous êtes à la tâche d’écrire ce qui revient à un analyseur HTML dédié, spécialement conçu, à partir de regex. La plupart des gens ne le sont pas.

Mais I am. ☻


Solutions générales d'analyse HTML basées sur Regex

Je vais d’abord montrer à quel point il est facile d’analyser du HTML arbitraire avec des expressions rationnelles. Le programme complet se trouve à la fin de cette publication, mais le cœur de l’analyseur est le suivant:

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

Voyez comment est facile à lire?

Tel qu'écrit, il identifie chaque morceau de HTML et indique où il a trouvé ce morceau. Vous pouvez facilement le modifier pour faire ce que vous voulez avec n'importe quel type de pièce ou pour des types plus particuliers que ceux-ci.

Je n'ai pas de scénario de test qui a échoué (à gauche :): J'ai réussi à exécuter ce code sur plus de 100 000 fichiers HTML - tous ceux sur lesquels je pouvais rapidement et facilement mettre la main. Au-delà, je l’exécute également sur des fichiers spécialement construits pour décomposer des analyseurs naïfs.

Ceci est pas un analyseur naïf.

Oh, je suis sûr que ce n’est pas parfait, mais je n’ai pas encore réussi à le casser. Je pense que même si quelque chose se produisait, le correctif serait facile à intégrer en raison de la structure claire du programme. Même les programmes lourds en regex devraient avoir une structure.

Maintenant que cela est réglé, laissez-moi répondre à la question du PO.

Démonstration de la résolution de la tâche du PO à l’aide de regex

Le petit programme html_input_rx que j'inclus ci-dessous produit le résultat suivant, de sorte que vous pouvez voir que l'analyse de HTML avec des expressions rationnelles fonctionne parfaitement pour ce que vous souhaitez faire:

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

Analyser les balises d'entrée, voir Aucune entrée malveillante

Voici la source du programme qui a généré la sortie ci-dessus.

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

Voilà! Rien pour le faire! :)

Seul vous pouvez juger si votre compétence avec les expressions rationnelles est à la hauteur d'une tâche d'analyse particulière. Le niveau de compétence de chacun est différent et chaque nouvelle tâche est différente. Pour les tâches pour lesquelles vous avez un jeu d’entrées bien défini, les expressions rationnelles sont évidemment le bon choix, car il est facile de les assembler lorsque vous avez un sous-ensemble restreint de HTML à traiter. Même les débutants en expression rationnelle devraient être capables de gérer ces tâches avec des expressions rationnelles. Tout le reste est exagéré.

Cependant , une fois que le code HTML commence à devenir moins clair, une fois qu'il commence à se ramifier d'une manière que vous ne pouvez pas prédire mais qui sont parfaitement légales, une fois que vous devez faire correspondre Si vous utilisez des dépendances plus complexes ou plus diverses, vous finirez par atteindre un point où vous devez travailler plus fort pour créer une solution utilisant des expressions rationnelles plutôt que d'utiliser une classe d'analyse syntaxique. Là où ce seuil de rentabilité tombe dépend encore une fois de votre propre niveau de confort avec les expressions rationnelles.

Donc qu'est ce que je devrais faire?

Je ne vais pas vous dire ce que vous devez faire ou ce que vous ne pouvez pas faire. Je pense que c’est faux. Je veux juste vous présenter des possibilités, ouvrez un peu les yeux. Vous devez choisir ce que vous voulez faire et comment vous voulez le faire. Il n'y a pas d'absolu - et personne d'autre ne connaît votre propre situation aussi bien que vous-même. Si quelque chose semble être trop de travail, eh bien, c’est peut-être le cas. La programmation devrait être fun , vous savez. Si ce n’est pas le cas, vous le faites peut-être mal.

On peut regarder mon programme html_input_rx de plusieurs façons valables. L'une d'elles est que vous pouvez analyser HTML avec des expressions régulières. Mais un autre problème est qu’il est beaucoup, beaucoup, beaucoup plus difficile que presque tout le monde ne le pense. Cela peut facilement mener à la conclusion que mon programme est un testament de ce que vous devriez ne pas faire , parce que c'est vraiment trop difficile.

Je ne suis pas en désaccord avec ça. Bien sûr, si tout ce que je fais dans mon programme n’a pas de sens pour vous après quelques études, vous ne devriez pas essayer d’utiliser des regex pour ce genre de tâche. Pour le HTML spécifique, les expressions rationnelles sont excellentes, mais pour le HTML générique, elles équivalent à de la folie. J’utilise tout le temps des classes d’analyse, surtout si c’est du HTML que je n’ai pas créé moi-même.

Regexes optimales pour petits problèmes d'analyse HTML, pessimaux pour les grands

Même si mon programme est pris pour illustrer pourquoi vous devriez ne pas utiliser des expressions rationnelles pour analyser le code HTML général - ce qui est OK, car je voulais plutôt que ce soit le cas. cela ☺ - cela devrait toujours être une révélation pour que plus de gens brisent la terrible habitude terriblement commune et méchante d'écrire des modèles illisibles, non structurés et non maintenables.

Les modèles ne doivent pas forcément être laids, ni durs. Si vous créez des motifs laids, c'est une réflexion sur vous, pas sur eux.

Un langage de regex phénoménalement exquis

On m’a demandé de préciser que la solution que j’avais proposée pour résoudre votre problème avait été écrite en Perl. Êtes-vous surpris? Avez-vous pas remarqué? Est-ce que cette révélation est une bombe?

Je dois avouer que je trouve cette demande à l'extrême, , car quiconque ne peut pas comprendre cela en regardant la toute première ligne de mon programme a sûrement d'autres handicaps mentaux. bien.

Il est vrai que tous les autres outils et langages de programmation ne sont pas aussi pratiques, expressifs et puissants en termes de regex que Perl. Il existe un large spectre, certains étant plus appropriés que d’autres. En général, il est plus facile de travailler avec les langages qui ont exprimé des expressions rationnelles comme faisant partie du langage principal plutôt que comme une bibliothèque. Je n’ai rien fait avec les expressions rationnelles que vous ne pouviez pas faire dans, disons, PCRE, bien que vous structuriez le programme différemment si vous utilisiez C.

Éventuellement, d'autres langues seront à la hauteur de Perl en termes de regex. Je dis cela parce que lorsque Perl a commencé, personne d’autre n’avait rien de comparable aux regex de Perl. Dites ce que vous voulez, mais Perl a clairement gagné: tout le monde a copié les expressions rationnelles de Perl, mais à différentes étapes de leur développement. Perl a été le pionnier de presque (pas tout à fait, mais presque) de tout ce sur quoi vous vous basez aujourd'hui dans les modèles modernes, quel que soit l'outil ou la langue que vous utilisez. Alors finalement, les autres vont se rattraper.

Mais ils ne rattraperont Perl que par le passé, tout comme c’est le cas actuellement. Tout avance. Dans les expressions rationnelles si rien d'autre, où Perl mène, les autres suivent. Où sera Perl une fois que tout le monde aura finalement retrouvé Perl? Je n'en ai aucune idée, mais je sais que nous aussi aurons déménagé. Nous serons probablement plus proches de le style de fabrication de Perl .

Si vous aimez ce genre de chose mais que vous souhaitez l'utiliser en Perl₅, vous pourriez être intéressé par Damian Conway's wonderful Regexp :: Grammars module. C’est tout à fait génial et donne à ce que j’ai fait ici dans mon programme une apparence aussi primitive que la mienne crée les motifs que les gens écrivent ensemble sans identificateurs d’espace ou alphabétiques. Vérifiez-le!


Simple HTML Chunker

Voici la source complète pour l'analyseur dont j'ai montré la pièce maîtresse au début de cette publication.

Je ne suggère pas que vous devriez utiliser ceci sur une classe d'analyse syntaxique rigoureusement testée. Mais j'en ai assez des gens qui prétendent que personne ne peut analyser HTML avec des regex simplement parce que ils ne le peuvent pas. Vous pouvez clairement le faire, et ce programme est la preuve de cette affirmation.

Bien sûr, ce n’est pas facile, mais cela est possible!

Et essayer de le faire est une perte de temps terrible, car il existe de bonnes classes d'analyse que vous devriez utiliser pour cette tâche. La bonne réponse à ceux qui essaient d'analyser arbitraires le HTML n'est pas qu'il est impossible. C'est une réponse facile et hypocrite. La réponse correcte et honnête est qu’ils ne devraient pas essayer, c’est trop compliqué de partir de zéro; ils ne devraient pas se casser le dos en essayant de réinventer une roue qui fonctionne parfaitement bien.

En revanche, le HTML qui tombe dans un sous-ensemble prédicable est extrêmement facile à analyser avec des expressions rationnelles. Il n’est pas étonnant que les gens essaient de les utiliser car, pour les petits problèmes, les problèmes de jouets peut-être, rien n’est plus facile. C’est pourquoi il est si important de distinguer les deux tâches - spécifique et générique - car elles n’exigent pas nécessairement la même approche.

J'espère voir à l'avenir un traitement plus juste et honnête des questions concernant HTML et les expressions rationnelles.

Voici mon lexer HTML. Il n’essaie pas de faire une analyse de validation; il identifie simplement les éléments lexicaux. Vous pourriez penser à cela davantage comme un chunker HTML qu'un analyseur HTML. Cela ne pardonne pas vraiment le HTML cassé, bien que cela ne tienne que très peu dans ce sens.

Même si vous n'analysez jamais vous-même l'intégralité du code HTML (et pourquoi le devriez-vous? C'est un problème résolu!), Ce programme contient de nombreux éléments de regex intéressants dont beaucoup de gens peuvent apprendre beaucoup à mon avis. Prendre plaisir!

#!/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. Vous pouvez écrire un roman comme tchrist
  2. Vous pouvez utiliser une bibliothèque DOM, charger le code HTML, utiliser xpath et utiliser simplement //input[@type="hidden"]. Ou si vous ne voulez pas utiliser xpath, récupérez toutes les entrées et filtrez celles qui sont masquées avec getAttribute.

Je préfère # 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>';
}

Résultat:

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

Dans l'esprit de la solution lexer de Tom Christiansen, voici un lien vers l'article apparemment oublié de 1998 de Robert Cameron, REX: XML Shallow Parsing with Regular Expressions.

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

Abstrait

La syntaxe de XML est suffisamment simple pour qu'il soit possible d'analyser un document XML dans une liste de ses éléments de balisage et de texte à l'aide d'une seule expression régulière. Une telle analyse superficielle d’un document XML peut s’avérer très utile pour la construction de nombreux outils de traitement XML légers. Cependant, les expressions régulières complexes peuvent être difficiles à construire et encore plus difficiles à lire. Utilisant une forme de programmation alphabète pour les expressions régulières, cet article documente un ensemble d'expressions d'analyse syntaxique XML superficielle pouvant servir de base à une analyse syntaxique XML simple, correcte, efficace, robuste et indépendante du langage. Des implémentations complètes d'analyseur superficiel de moins de 50 lignes chacune en Perl, JavaScript et Lex/Flex sont également présentées.

Si vous aimez lire sur les expressions régulières, le papier de Cameron est fascinant. Son écriture est concise, complète et très détaillée. Il ne vous montre pas simplement comment construire l'expression régulière REX, il vous propose également une approche permettant de créer des expressions rationnelles complexes à partir de parties plus petites.

Cela fait 10 ans que j'utilise l'expression régulière REX de façon répétée pour résoudre le type de problème que l'affiche initial posait (comment puis-je associer cette étiquette à une autre, mais pas à une autre étiquette très similaire?). J'ai trouvé que la regex qu'il avait développée était complètement fiable.

REX est particulièrement utile lorsque vous vous concentrez sur les détails lexicaux d'un document - par exemple, lorsque vous transformez un type de document texte (par exemple, du texte brut, XML, SGML, HTML) en un autre, où le document peut ne pas être valide. bien formé, voire analysable pour la majeure partie de la transformation. Il vous permet de cibler des îlots de balisage n'importe où dans un document sans perturber le reste du document.

20
David

Bien que j'aime le contenu du reste de ces réponses, elles n'ont pas vraiment répondu à la question directement ou de manière aussi correcte. Même la réponse de Platinum était trop compliquée et moins efficace. Alors j'ai été obligé de mettre ça.

Je suis un grand partisan de Regex, lorsqu'il est utilisé correctement. Mais à cause de la stigmatisation (et des performances), je déclare toujours que XML ou HTML bien formé devrait utiliser un analyseur XML. Et des performances encore meilleures seraient l'analyse de chaînes, bien qu'il y ait une marge entre la lisibilité si cela devient trop incontrôlable. Cependant, ce n'est pas la question. La question est de savoir comment faire correspondre une balise d’entrée de type caché. La réponse est:

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

Selon votre goût, la seule option de regex que vous auriez besoin d'inclure est l'option ignorecase.

5
Suamere

vous pouvez essayer ceci:

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

et pour un résultat plus proche, vous pouvez essayer ceci:

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

vous pouvez tester votre motif de regex ici/ http://regexpal.com/

ces modèles sont bons pour cela:

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

et pour un ordre aléatoire de type, name et value, vous pouvez utiliser ceci:

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

ou

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

sur ce :

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

`

en passant, je pense que vous voulez quelque chose comme ça:

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

ce n'est pas bon mais cela ne fonctionne d'aucune façon.

testez-le dans: http://regexpal.com/

2
Shamshirsaz.Navid

Je voudrais utiliser **DOMDocument** pour extraire le code 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, vous pouvez le tester ici - regex101.com. Il affiche le résultat en temps réel . Quelques règles concernant Regexp: http://www.Eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html. Lecteur .

1
HTML5 developer

supposons que votre contenu html soit stocké dans une chaîne html, vous pouvez utiliser une expression régulière pour obtenir toutes les entrées contenant du type masqué

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

la regex ci-dessus trouve <input suivi d'un nombre quelconque de caractères jusqu'à l'obtention de type="hidden" ou d'un type = 'caché' suivi d'un nombre quelconque de caractères jusqu'à l'obtention de >

/ g indique à l'expression régulière de trouver chaque sous-chaîne correspondant au modèle donné.

0
Nitin9791