201 votes

Modèle d'expression régulière ne correspondant à aucune chaîne

Je suis en train de faire correspondre <input> de type "hidden" champs à l'aide de ce modèle:

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

C'est un exemple de formulaire de données:

<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 l' type, name, et value attributs apparaissent toujours dans le même ordre. Si l' type attribut est le dernier, le match va échouer parce que dans mon modèle, c'est au début.

Question:
Comment puis-je changer mon modèle, donc il va correspondre quelle que soit la position des attributs de l' <input> balise?

P. S.: je suis en utilisant le logiciel Adobe Air en fonction RegEx Outil de Bureau pour tester les expressions régulières.

726voto

tchrist Points 47116

Oh Oui, Vous Pouvez Utiliser les Regexes pour Parser du HTML!

Pour la tâche que vous essayez, regexes sont parfaitement bien!

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

Mais ce n'est pas une faille fondamentale liée à la théorie de calcul. Que la bêtise est effacèrent beaucoup ici, mais ne croyez-vous pas.

Ainsi, alors qu'il peut certainement être fait (cet affichage sert de preuve de l'existence de ce fait incontestable), qui ne signifie pas qu'il devrait être.

Vous devez décider pour vous-même si vous êtes à la hauteur de la tâche d'écriture ce qui équivaut à un dédié, à des fins spéciales de l'analyseur HTML de regexes. La plupart des gens ne le sont pas.

Mais je suis. ☻


EDIT: Général Regex HTML Basés sur l'Analyse des Solutions

D'abord, je vais vous montrer comment il est facile d'analyser arbitraire HTML avec regexes. Le programme complet est à la fin de cette annonce, mais le cœur de l'analyseur est:

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

Voir comment facile qui consiste à lire?

Comme l'a écrit, il identifie chaque morceau de HTML et indique où il a trouvé cette pièce. Vous pouvez facilement le modifier pour faire ce que vous voulez avec n'importe quel type de pièce, ou pour plus de types particuliers de ces.

Je n'ai pas de défaut cas de test (à gauche :): j'ai réussi à exécuter ce code sur plus de 100 000 fichiers HTML - tous seul je pouvais facilement et rapidement obtenir mes mains sur. Au-delà de ces domaines, j'ai aussi l'exécuter sur les fichiers spécialement conçus pour briser naïf d'analyseurs.

Ce n'est pas un naïf de l'analyseur.

Oh, je suis sûr qu'il n'est pas parfait, mais je n'ai pas réussi à le briser encore. Je me dis que même si quelque chose l'a fait, la solution serait facile de s'intégrer en raison de la structure claire. Même regex lourde les programmes doivent avoir stucture.

Maintenant que cela est hors de la voie, laissez-moi répondre à l'OP de la question.

Démonstration de la Résolution de l'OP de la Tâche à l'Aide de Regexes

Le peu d' html_input_rx program-je inclure ci-dessous génère la sortie suivante, de sorte que vous pouvez voir que l'analyse HTML avec regexes fonctionne très bien pour ce que vous voulez 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 Input, Ne Pas Voir Le Mal D'Entrée

Voici le code source du programme qui a produit le résultat ci-dessus.

#!/usr/bin/env perl
#
# html_input_rx - pull out all <input> tags from (X)HTML src
#                  via simple regex processing
#
# Tom Christiansen <tchrist@perl.com>
# 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: $!";
} 

Là vous allez! Rien à! :)

Seulement vous pouvez juger si votre habileté avec les regexes est à tout particulier à l'analyse de la tâche. Le niveau de compétence est différente, et chaque nouvelle tâche est différente. Pour les emplois où vous avez une bien défini d'entrée de jeu, regexes sont de toute évidence le bon choix, parce que c'est facile à mettre ensemble quand vous avez un sous-ensemble restreint de HTML à traiter. Même regex pour les débutants doivent être traiter ces emplois avec regexes. Tout le reste est inutile.

Cependant, une fois que le HTML commence à devenir de moins en moins à clouer, une fois qu'il commence à se ramifier dans les moyens que vous ne peut pas prédire, mais qui sont parfaitement légales, une fois que vous avez à correspondre à plus de différentes sortes de choses ou avec dépendances plus complexe, vous finirez par atteindre un point où vous devez travailler plus dur pour effet une solution qui utilise les regexes que vous auriez à l'aide d'une analyse de classe. Où que le break-even point de chute dépend encore une fois sur votre propre niveau de confort avec regexes.

Alors Que Dois-Je Faire?

Je ne vais pas vous dire ce que vous devez faire ou ce que vous ne peut pas faire. Je pense que c'est Faux. Je veux juste vous présenter possibilités, ouvrez les yeux un peu. Vous aurez à choisir ce que vous voulez faire et comment vous voulez le faire. Il n'y a pas d'absolus - et personne d'autre ne sait votre propre situation ainsi que vous-même faire. Si quelque chose semble trop de travail, peut-être qu'il est. La programmation doit être amusant, vous savez. Si ce n'est pas le cas, vous pouvez avoir tout faux.

On peut regarder mon html_input_rx programme dans un certain nombre de moyens valables. Un exemple est que vous pouvez analyser HTML avec des expressions régulières. Mais une autre est que c'est beaucoup, beaucoup, beaucoup plus difficile que presque tout le monde pense jamais qu'il est. Cela peut facilement conduire à la conclusion que mon programme est un témoignage de ce que vous devriez pas faire, parce que c'est vraiment trop dur.

Je ne vais pas en désaccord avec cela. Certes, si tout ce que je fais dans mon programme ne fait pas de sens pour vous après certaines études, alors vous ne devriez pas tenter d'utiliser regexes pour ce genre de tâche. Pour HTML, regexes sont super, mais pour le générique de HTML, ils sont l'équivalent de la folie. J'utilise l'analyse des classes de tous les temps, surtout si c'est du HTML, je n'ai pas généré de moi-même.

Regexes optimale pour les petites HTML problèmes de l'analyse, pessimal pour les grandes

Même si mon programme est pris comme une illustration de pourquoi vous devriez ne pas utiliser regexes pour l'analyse générale HTML qui est ok, parce que j'ai un peu destinés à être - il encore ouvert les yeux de sorte que plus de gens se cassent le terriblement commun et méchant, méchante habitude de l'écriture illisible, non structurées, et difficile à maintenir les modèles.

Les modèles n'ont pas à être laid, et ils n'ont pas à être difficile. Si vous créez laid modèles, c'est une réflexion sur vous, pas pour eux.

Incroyablement Exquis Regex Langue

J'ai demandé à souligner que mes proferred solution à votre problème a été écrit en Perl. Êtes-vous surpris? N'avez-vous pas remarqué? Est-ce la révélation d'une bombe?

Je dois avouer que je trouve cette demande bizarre à l'extrême, puisque quelqu'un qui ne peut pas le savoir en regardant la première ligne de mon programme a sûrement d'autres handicaps mentaux.

Il est vrai que tous les autres outils et langages de programmation sont tout aussi pratique, expressif et puissant quand il s'agit de regexes que Perl est. Il y a un grand spectre de là, certains étant plus adaptées que d'autres. En général, les langues qui ont exprimé regexes dans le cadre de la linguistique de base, plutôt que comme une bibliothèque sont plus faciles à travailler avec. Je n'ai rien fait avec regexes que vous ne pouvait pas faire, dire, PCRE, bien que vous la structure du programme différemment si vous étiez à l'aide de C.

Finalement, d'autres langues seront rattraper où Perl est maintenant en termes de regexes. Je dis cela parce que, quand Perl a commencé, personne d'autre n'avait rien comme Perl regexes. Dire ce que vous voulez, mais c'est là que Perl clairement gagné: tout le monde a copié Perl regexes mais à des stades différents de leur développement. Perl est le pionnier presque (mais pas tout à tous, mais presque) tout ce que vous avez appris à compter sur les tendances modernes aujourd'hui, n'importe quel outil ou la langue que vous utilisez. Donc finalement, les autres vont le rattraper.

Mais ils ne se rattraper où Perl est un moment du passé, tout comme il est maintenant. Tout progrès. Dans regexes si rien d'autre, où Perl conduit, d'autres suivent. Où vais-Perl-être une fois tout le monde enfin captures où Perl est maintenant? Je n'ai aucune idée, mais je sais que nous aussi nous avons déménagé. Probablement, nous allons être plus proche de Perl₆ du style de l'artisanat des modèles.

Si vous aimez ce genre de chose, mais que vous souhaitez l'utiliser Perl₅, vous pourriez être intéressé par Damian Conway merveilleux Regexp::Grammaires module. C'est complètement génial, et fait ce que j'ai fait ici, dans mon programme semble tout aussi primitive que la mienne fait les modèles qui s'entassent sans espaces ou alphabétique identifiants. Check it out!


EDIT: HTML Simple Chunker

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

Je suis pas ce qui suggère que vous devriez l'utiliser sur un rigoureusement testé l'analyse de classe. Mais je suis fatigué de gens qui font semblant que personne ne peut analyser HTML avec regexes juste parce qu' ils ne le peuvent pas. De toute évidence, vous pouvez, et ce programme est la preuve de cette affirmation.

Bien sûr, il n'est pas facile, mais c' est possible!

Et en essayant de le faire est une terrible perte de temps, car une bonne analyse des classes existent dont vous devriez utiliser pour cette tâche. Le droit de réponse des personnes qui tentent d'analyser arbitraire HTML, c'est pas que c'est impossible. C'est une facile et hypocrite réponse. La bonne et la réponse honnête est qu'ils ne devraient pas essayer parce que c'est trop de la peine à comprendre à partir de zéro; ils ne doivent pas casser le dos en s'efforçant de reïnvent une roue qui fonctionne parfaitement bien.

D'autre part, le code HTML qui tombe à l'intérieur d'un prévisible sous-ensemble est ultra-facile à analyser avec regexes. Il n'est pas étonnant que les gens essaient de les utiliser, parce que pour les petits problèmes, jouet des problèmes peut-être, rien ne pourrait être plus facile. C'est pourquoi il est si important de distinguer les deux tâches spécifiques vs générique - si elles ne sont pas nécessairement à la demande de la même démarche.

J'espère que dans le futur ici pour voir une plus juste et honnête, le traitement de questions sur le langage HTML et les regexes.

Voici mon code HTML lexer. Il n'essayez pas de faire une validation d'analyser; simplement, il identifie les éléments lexicaux. Vous pourriez penser qu'il est plus que HTML chunker qu'un analyseur HTML. Il n'est pas très facile à cassé HTML, bien qu'il en fait des très petites indemnités dans cette direction.

Même si vous n'avez jamais analyser HTML vous-même (et pourquoi devriez-vous? c'est un problème résolu!), ce programme a beaucoup de fraîcheur des regex peu que je crois que beaucoup de gens peuvent apprendre beaucoup. Profitez-en!

#!/usr/bin/env perl
#
# chunk_HTML - a regex-based HTML chunker
#
# Tom Christiansen <tchrist@perl.com
#   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 }

131voto

meder Points 81864
<ol> <li>Vous pouvez écrire qu'un roman comme tchrist fait</li> <li>Vous pouvez utiliser une bibliothèque de DOM, charger le code HTML et utiliser xpath et il suffit d’utiliser <code></code> . Ou si vous ne voulez pas utiliser xpath, juste obtenir toutes les entrées et filtre ceux qui est cachés avec <code></code> .</li> <p>Je préfère #2.</p><pre><code></code></pre><p>Résultat :</p><pre><code></code></pre></ol>

113voto

Platinum Azure Points 22380

Contrairement à toutes les réponses ici, pour ce que vous essayez de faire des regex est une parfaite solution valable. C'est parce que vous n'êtes PAS d'essayer de match équilibré tags-- QUI serait impossible avec les regex! Mais vous êtes le seul qui correspond à ce qui est dans une balise, et c'est parfaitement régulière.

Voici le problème, cependant. Vous ne pouvez pas le faire avec une seule regex... vous avez besoin de faire un match à la capture d'un <input> balise, puis poursuivre le traitement sur cette. Notez que cela ne fonctionne que si aucune des valeurs d'attribut ont un > de caractères en eux, de sorte qu'il n'est pas parfait, mais ça devrait suffire pour sane entrées.

Voici quelques Perl (pseudo -) code 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 ici, n'essayez pas d'en faire trop avec une expression régulière. Comme vous l'avez remarqué, les expressions régulières respecter un certain montant de commande. Donc, ce que vous devez faire à la place est au premier match le CONTEXTE de ce que vous essayez d'extraire, puis faire submatching sur les données que vous souhaitez.

EDIT: Cependant, je suis d'accord qu'en général, à l'aide d'un analyseur HTML est probablement plus facile et mieux et vous devriez vraiment envisager de modifier votre code ou de ré-examen de vos objectifs. :-) Mais j'ai dû poster cette réponse comme un compteur à le réflexe que l'analyse à un sous-ensemble du langage HTML est impossible: HTML et XML sont à la fois irrégulière lorsque l'on considère l'ensemble de la spécification, mais la spécification d'une balise est décemment régulière, certainement à l'intérieur de la puissance de PCRE.

22voto

David Points 393

Dans l'esprit de Tom Christiansen du lexer solution, voici un lien vers Robert Cameron, apparemment oublié 1998 article, REX: XML Shallow Parsing avec des Expressions Régulières.

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

Résumé

La syntaxe de XML est assez simple qu'il est possible d'analyser un document XML dans une liste de son marquage et des éléments de texte à l'aide d'une seule expression régulière. Une telle shallow parser un document XML peut être très utile pour la construction d'une variété de XML léger outils de traitement. Cependant, complexe des expressions régulières peut être difficile à construire et encore plus difficile à lire. À l'aide d'un formulaire d'alphabétisation de programmation pour les expressions régulières, ce document décrit un ensemble de XML shallow parsing des expressions qui peuvent être utilisés d'une base simple, correct, efficace, robuste et indépendant du langage XML shallow parsing. Complet shallow parser implémentations de moins de 50 lignes de chaque en Perl, JavaScript et Lex/Flex sont également donnés.

Si vous aimez lire sur les expressions régulières, Cameron, le papier est fascinant. Son écriture est concise, complète et très détaillée. Il n'est pas simplement de vous montrer comment construire le REX de l'expression régulière, mais aussi une approche pour la construction d'un complexe regex de petites pièces.

J'ai été en utilisant le REX expression régulière sur et en dehors pendant 10 ans pour résoudre le problème initial de l'affiche demandé à ce sujet (comment puis-je correspond à ce tag, mais pas une autre très similaire tag?). J'ai trouvé la regex qu'il a développé pour être totalement fiable.

REX est particulièrement utile lorsque vous êtes en se concentrant sur lexicale des détails d'un document (par exemple, lors de la transformation d'un type de document texte (p. ex., texte, XML, SGML, HTML) dans un autre, où le document peut ne pas être valide, bien formé, ou même être analysée pour la plupart de la transformation. Il vous permet de cibler les îles de balisage n'importe où dans un document sans déranger le reste du document.

9voto

Suamere Points 694

Alors que j'adore le contenu du reste de ces réponses, ils n'ont pas vraiment répondre à la question directement ou en tant que correctement. De Platine, même de la réponse était trop compliqué, et également moins efficace. J'ai donc été forcé de mettre cette.

Je suis un grand partisan de la Regex, lorsqu'il est utilisé correctement. Mais à cause de la stigmatisation (et de la performance), j'ai toujours l'état qui XML bien formé ou HTML doit utiliser un Analyseur XML. Et une performance encore meilleure serait de la chaîne d'analyse, si il ya une ligne entre la lisibilité si c'est trop hors de la main. Cependant, ce n'est pas la question. La question est de savoir comment faire correspondre un caché-type de la balise input. La réponse est:

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

Selon votre goût, la seule option de type expression régulière, vous aurez besoin de comprendre ce qui ignorecase option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X