web-dev-qa-db-ja.com

正規表現パターンが文字列のどこにも一致しませんか?

このパターンを使用して、<input>タイプの「非表示」フィールドを照合しようとしています。

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

これはサンプルフォームデータです。

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

ただし、typename、およびvalue属性が常に同じ順序で表示されるかどうかはわかりません。 type属性が最後に来ると、パターンで開始されるため、一致は失敗します。

質問:
パターンを変更して、<input>タグ内の属性の位置に関係なく一致させるにはどうすればよいですか?

PS:ところで、私はAdobe Airベースの RegEx Desktop Tool 正規表現のテスト用。

174
Salman

ここでのすべての答えに反して、正規表現をしようとしているのは完全に有効なソリューションです。これは、バランスの取れたタグを一致させようとしないためです。正規表現では不可能です。ただし、1つのタグにあるものと一致するだけで、それは完全に規則的です。

ただし、ここに問題があります。正規表現を1つだけ使用することはできません... <input>タグをキャプチャするために1つの一致を実行し、さらに処理する必要があります。これは、属性値に>文字が含まれていない場合にのみ機能するため、完全ではありませんが、正常な入力で十分なことに注意してください。

以下に、私が意味することを示すPerl(擬似)コードを示します。

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
}

ここでの基本原則は、1つの正規表現でやりすぎないことです。お気づきのとおり、正規表現は一定の順序を強制します。そのため、代わりに行う必要があるのは、抽出しようとしているもののCONTEXTを最初に一致させ、次に必要なデータで部分一致を実行することです。

編集: ただし、一般に、HTMLパーサーを使用する方が簡単で優れているため、コードの再設計や目的の再検討を検討する必要があることに同意します。 :-)しかし、HTMLのサブセットを解析することは不可能であるというニージャークな反応に対するカウンターとして、この回答を投稿する必要がありました。 、確かにPCREの力の範囲内です。

106
Platinum Azure

Oh Yes You Can正規表現を使用してHTMLを解析します!

あなたがしようとしているタスクの場合、正規表現は完全に問題ありません!

is trueの場合、ほとんどの人はHTMLを正規表現で解析することの難しさを過小評価しており、そのため貧弱です。

しかし、これは計算理論に関連する根本的な欠陥ではありません。この愚かさはこの辺りで多く見られますが、信じてはいけません。

したがって、確かにそれを行うことができますが(この投稿はこの議論の余地のない事実の存在証明として機能します)、それはそれを意味するわけではありませんshould.

正規表現のうち、専用の特別な目的のHTMLパーサーを作成するタスクを実行するかどうかを自分で決定する必要があります。ほとんどの人はそうではありません。

しかしI amです。 ☻


一般的な正規表現ベースのHTML解析ソリューション

最初に、正規表現を使用した任意のHTMLの解析がいかに簡単かを示します。完全なプログラムはこの投稿の最後にありますが、パーサーの中心は次のとおりです。

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

easyの読み方をご覧ください。

書かれているように、HTMLの各部分を識別し、その部分を見つけた場所を伝えます。特定のタイプのピースで、またはこれらよりも特定のタイプで、他に何でもやりたいように簡単に変更できます。

失敗したテストケースはありません(左:):100,000を超えるHTMLファイルでこのコードを正常に実行しました。すべてのファイルをすばやく簡単に手に入れることができました。さらに、ファイルに対しても実行しました特定的に構築ナイーブパーサーを破壊します。

これはnotナイーブパーサーです。

ああ、それは完璧ではないと確信していますが、まだそれを破ることができていません。たとえ何かが起こったとしても、プログラムの構造が明確であるため、修正は簡単に適合すると思います。正規表現が多いプログラムでも構造が必要です。

これで問題は解決しましたので、OPの質問に答えましょう。

正規表現を使用してOPのタスクを解決するデモ

以下に含まれる小さなhtml_input_rxプログラムは、次の出力を生成します。これにより、正規表現を使用したHTMLの解析が、目的どおりに機能することがわかります。

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

入力タグの解析、邪悪な入力なし

上記の出力を生成したプログラムのソースは次のとおりです。

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

行くぞ!それに何もない! :)

yoのみが、正規表現のスキルが特定の解析タスクに依存しているかどうかを判断できます。全員のスキルレベルは異なり、新しいタスクはすべて異なります。明確に定義された入力セットがあるジョブの場合、正規表現は明らかに正しい選択です。なぜなら、処理するHTMLの制限されたサブセットがある場合、いくつかをまとめるのは簡単だからです。正規表現の初心者であっても、正規表現を使用してこれらのジョブを処理する必要があります。それ以外は過剰です。

ただし、、HTMLの釘付けが少なくなり始めると、予測できない方法で分岐し始めますが、一致する必要がある場合は完全に合法ですより多くの異なる種類の、またはより複雑な依存関係があると、最終的には、解析クラスを使用するよりも正規表現を使用するソリューションを実現するために一生懸命働く必要があります。その損益分岐点がどこに落ちるかは、正規表現に対するあなた自身の快適さのレベルに依存します。

だから私は何をすべきですか?

私はあなたが何をするのかmustやあなたがcannot何をするのか教えません。それは間違っていると思います。私はあなたに可能性を提示したい、少し目を開けてください。何をしたいのか、どのようにしたいのかを選択できます。絶対的なものはありません。そして、あなた自身と同じようにあなた自身の状況を他の誰も知りません。作業が多すぎるように思われる場合は、そうかもしれません。プログラミングはfunである必要があります。そうでない場合は、間違っている可能性があります。

私のhtml_input_rxプログラムを有効な方法で見ることができます。その1つは、実際にcan正規表現でHTMLを解析することです。しかし、もう1つは、ほとんどの人が思っているよりもはるかに難しいということです。これは私のプログラムがあなたがすべきことの証であるという結論に簡単に導くことができますnotするのは本当に難しいからです。

私はそれに反対しません。確かに、私のプログラムで私がすることのすべてが何らかの研究の後にあなたにとって意味をなさないならば、あなたはこの種のタスクのために正規表現を使用しようとすべきではありません。特定のHTMLの場合、正規表現は優れていますが、汎用HTMLの場合、それらは狂気に匹敵します。特に自分で生成していないHTMLの場合は、常に解析クラスを使用します。

small HTML解析問題に最適な正規表現、大規模なものには悲観的

私のプログラムが、なぜnotである必要があるのか​​を説明するものとして解釈されたとしても、一般的なHTMLの解析に正規表現を使用します。 ☺—それはまだ目を見張るものでなければならないので、読めない、構造化されていない、維持できないパターンを書くというひどく一般的で厄介で厄介な習慣を破る人が増えます。

パターンはいものである必要はありませんし、難しいものである必要もありません。いパターンを作成する場合、それはあなたではなく、あなたに反映されます。

驚異的に絶妙な正規表現言語

あなたの問題に対する私の推奨される解決策はPerlで書かれていることを指摘するように頼まれました。驚きましたか?気づかなかった?この啓示は爆弾ですか?

私はこの要求を見つけたことを告白しなければなりません極端な奇妙な私のプログラムの最初の行を見てそれを理解できない人は、他の精神障害も確かに持っているからです。

他のすべてのツールやプログラミング言語がPerlほど正規表現に関して非常に便利で、表現力があり、強力なわけではありません。そこには大きなスペクトルがあり、いくつかは他のものよりも適しています。一般に、ライブラリとしてではなくコア言語の一部として正規表現を表現した言語は、操作が簡単です。 Cを使用している場合はプログラムを別の方法で構成することはできますが、PCREなどでは実行できない正規表現は何も実行していません。

最終的には、他の言語がPerlの現在の正規表現に追いつくでしょう。これは、Perlが起動したとき、Perlの正規表現のようなものを誰も持っていなかったからです。好きなことを言ってください。しかし、ここでPerlが明確に勝ちました。開発のさまざまな段階ではありますが、誰もがPerlの正規表現をコピーしました。 Perlは、使用するツールや言語に関係なく、現代のパターンに依存するようになったほぼすべて(すべてではありませんが、ほぼすべて)を開拓しました。だから最終的に他の人will追いつく。

しかし、彼らは、今のように、Perlが過去のある時点に追いつくだけです。すべてが進歩します。 Perlがリードする正規表現では、他に何もなければ、他の人もそれに続きます。 Perlが、Perlが今いる場所についに追いついたら、Perlはどこにいるのでしょうか?私にはわからないが、私たちも動いたことはわかっている。おそらく Perl₆のクラフトパターンのスタイル に近いでしょう。

そのようなことが好きなのにPerl₅で使いたいなら、 Damian Conway'swonderfulRegexp :: Grammars モジュール。それは完全に素晴らしいですし、私のプログラムでここでやったことは、私が人々が空白やアルファベットの識別子なしで詰め込むパターンを作るのと同じように原始的に見えます。見てみな!


シンプルなHTMLチャンカー

これが、この投稿の冒頭で中心的な部分を示したパーサーの完全なソースです。

私はnot厳密にテストされた解析クラスでこれを使用することを提案しています。しかし、私はtheyできないという理由だけで、誰も正規表現でHTMLを解析できないというふりをする人にうんざりしています。明らかにできますし、このプログラムはその主張の証拠です。

確かに簡単ではありませんが、それはis可能です!

そして、そうすることはひどい時間の浪費です。なぜなら、このタスクに使用するshouldの良い解析クラスが存在するからです。 任意 HTMLを解析しようとする人々に対する正しい答えは、不可能ではないnotです。それは簡単で不誠実な答えです。正確で正直な答えは、彼らはそれを試みるべきではないということです。なぜなら、それは最初から理解するのが面倒だからです。完璧に機能するホイールを再発明するために努力を怠らないようにしてください。

一方、予測可能なサブセット内に該当するHTMLは、正規表現で解析するのが非常に簡単です。人々がそれらを使用しようとするのも不思議ではありません。小さな問題、おもちゃの問題については、おそらくこれ以上簡単なことはないからです。そのため、特定のアプローチと汎用の2つのタスクを区別することが非常に重要です。これらは必ずしも同じアプローチを必要としないためです。

将来的には、HTMLと正規表現に関する質問のより公平で正直な取り扱いを期待しています。

これが私のHTMLレクサーです。検証の解析は行いません。語彙要素を識別するだけです。 HTMLパーサーよりもHTMLチャンカーと考えるかもしれません。壊れたHTMLを許容することはあまりありませんが、その方向には非常に小さな余裕があります。

完全なHTMLを自分で解析したことがない場合(そして、なぜそうする必要があるのか​​?それは解決された問題です!)楽しい!

#!/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. Tchristのように小説を書くことができます
  2. DOMライブラリを使用し、HTMLをロードしてxpathを使用し、//input[@type="hidden"]を使用できます。または、xpathを使用したくない場合は、すべての入力を取得し、どの入力がgetAttributeで非表示になるかをフィルタリングします。

私は#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>';
}

結果:

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

トム・クリスチャンセンのレクサー・ソリューションの精神で、ここにロバート・キャメロンの忘れ去られたと思われる1998年の記事へのリンクがありますREX:XML Shallow Parsing with Regular Expressions。

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

抽象

XMLの構文は非常に単純であるため、単一の正規表現を使用してXMLドキュメントを解析して、マークアップおよびテキストアイテムのリストにすることができます。 XMLドキュメントのこのような浅い解析は、さまざまな軽量XML処理ツールの構築に非常に役立ちます。ただし、複雑な正規表現は作成するのが難しく、さらに読みにくい場合があります。このペーパーでは、正規表現にリテラシープログラミングの形式を使用して、シンプルで、正確で、効率的で、堅牢で、言語に依存しないXML浅い解析の基礎として使用できるXML浅い解析式のセットを文書化します。 Perl、JavaScript、Lex/Flexでそれぞれ50行未満の完全な浅いパーサー実装も提供されます。

正規表現についての読書を楽しんでいるなら、キャメロンの論文は魅力的です。彼の文章は簡潔で、徹底的で、非常に詳細です。彼は単にREX正規表現を作成する方法を示しているだけでなく、小さな部分から複雑な正規表現を構築するためのアプローチも示しています。

私は10年間、REX正規表現をオン/オフで使用して、最初のポスターが尋ねた種類の問題を解決しました(他の非常に類似したタグではなく、この特定のタグにどのように一致しますか?)。彼が開発した正規表現は完全に信頼できるものであることがわかりました。

REXは、ドキュメントの語彙の詳細に焦点を当てている場合に特に役立ちます。たとえば、ある種類のテキストドキュメント(プレーンテキスト、XML、SGML、HTMLなど)を別のドキュメントに変換する場合です。整形式であるか、ほとんどの変換で解析可能です。ドキュメントの残りの部分に影響を与えることなく、ドキュメント内のどこにでもマークアップの島をターゲットにできます。

20
David

私はこれらの答えの残りの内容が大好きですが、彼らは実際に直接または正確に質問に答えませんでした。 Platinumの答えでさえ、過度に複雑であり、効率も劣っていました。だから私はこれを置くことを余儀なくされました。

正しく使用すると、私はRegexの大きな支持者です。しかし、スティグマ(およびパフォーマンス)のため、整形式のXMLまたはHTMLはXMLパーサーを使用する必要があると常に述べています。さらにパフォーマンスは文字列解析になりますが、手に負えない場合は読みやすさの差があります。しかし、それは問題ではありません。問題は、非表示タイプの入力タグをどのように一致させるかです。答えは:

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

フレーバーに応じて、含める必要がある正規表現オプションはignorecaseオプションのみです。

5
Suamere

これを試すことができます:

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

より近い結果を得るには、これを試すことができます:

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

ここで正規表現パターンをテストできます http://regexpal.com/

これらのパターンはこれに適しています:

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

typenameおよびvalueのランダムな順序の場合、次を使用できます。

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

または

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

これについて:

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

`

ちなみに、私はあなたがこのようなものが欲しいと思う:

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

良くはありませんが、どんな形でも機能します。

でテスト: http://regexpal.com/

3

**DOMDocument**を使用して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') );
}

ところで、ここ-regex101.comでテストできます。結果をリアルタイムで表示します。 Regexpに関するいくつかのルール: http://www.Eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.htmlReader

1
HTML5 developer

あなたのhtmlコンテンツが文字列htmlに保存されていると仮定すると、隠されたタイプを含むすべての入力を取得するために、正規表現を使用できます

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

上記の正規表現は、<inputまたはtype = 'hidden'に続く任意の数の文字が続くtype="hidden"に続いて>になるまで任意の数の文字を見つけます

/ gは、指定されたパターンに一致するすべての部分文字列を検索するように正規表現に指示します。

0
Nitin9791