0

正規表現との混合結果、html コード内のフレーズのリストの一致

この新しい投稿は、複数の単語を含む Perl Regex match lines という別の投稿への返信でしたが、理由は不明ですが、モデレーターによって削除されました。元のスレッドで質問するのは理にかなっているように思えました。それは、そのスレッドの早い段階で提供された解決策を使用しようとする試みと、それに伴う問題に関係しているためです。faqへの一般的な参照がありましたが、これは矛盾を明らかにしていないようで、「質問がある場合は、独自の質問を投稿してください」というメッセージがありました。したがって、この投稿。

LWP::Simple を使用して Web ページを取得し、特定のフレーズを含む行を照合しようとしています。上記のスレッドの回答 #1の正規表現をコピーし、一致させる必要がある単語を置換または追加しましたが、似ているが異なる 2 つの Web ページでさまざまな結果が得られます。

私が使用している正規表現は次のとおりです。

/^(?=.*?\bYear\b)(?=.*?\bNew Moon\b)(?=.*?\bFirst Quarter\b)(?=.*?\bFull Moon\b)(?=.*?\bLast Quarter\b).*$/gim

タグで囲まれた一連のブロック内にこれらの単語を含む裸の行がある Web サイト #1 の場合、<pre>..</pre>予想どおり、これとまったく同じすべての行に一致します。

 Year        New Moon       First Quarter       Full Moon       Last Quarter

しかし、単語を囲む厄介な小さなタグがあるWebサイト#2の場合:

<br><br><span class="prehead"> Year      New Moon       First Quarter       Full Moon       Last Quarter          &#916;T</span><br>

それはすべての行に一致します!

タグはこれを行うための「適切な」方法であると確信してい<span>ますが、これらのタグを回避する方法を知りたいので、両方のサイトで正規表現を1つだけ持つことができます. これを行う簡単な方法はありますか、それともhtmlを解析する方法を学ぶ必要がありますか(私がする必要はありません)?

堅牢なソリューションではなく、迅速なソリューションを探しています。これはおそらく1回限りの取引です。これらの比較的静的なページが変更された場合、それはおそらくマイナーであり、簡単に修正できます。すべての 'anti-regex-for-html' ページを私に紹介しないでください。私はそれらを見てきました。そして、私に HTML::TreeBuilder を使わせないでください。あ、お願いします...

4

3 に答える 3

0

私の仮定が正しければ、特定の単語のシーケンスのみに一致させたいと思います。

Year        New Moon       First Quarter       Full Moon       Last Quarter

両端のタグに関係なく、自由な間隔で。

これを使用して、両端の適切にフォーマットされた開始タグと終了タグを一致させることができます

<[^>]*?>

つまり、開始"<"と最初の終了">"の間にある文字列はすべて

次に、これらのタグの間にスペースを入れるようにしたいので、両端の空白がゼロ以上の場合は空白インジケーター「\s*」を使用します。

\s*<[^>]*?>\s*

次に、それを非キャプチャ(効率のため)グループにグループ化し、0回以上繰り返させます。これは、タグが一致していることを確認するために正規表現の両端に配置するものです。

(?:\s*<[^>]*?>\s*)*

次に、フレーズの間に「\ s *」を使用して目的のテキストを入力し、スペースを確保し、フレーズ間にスペースのみが許可されるようにします。

(?:\s*<[^>]*?>\s*)*\s*Year\s*New Moon\s*First Quarter\s*Full Moon\s*Last Quarter\s*(?:\s*<[^>]*?>\s*)*

次に、行の開始行と終了行のマーカーで終了します

/^(?:\s*<[^>]*?>\s*)*\s*Year\s*New Moon\s*First Quarter\s*Full Moon\s*Last Quarter\s*(?:\s*<[^>]*?>\s*)*$/gim

これは、目的のフレーズの両端に任意の数のタグを含む行と一致する必要がありますが、追加の文字など、他に何かが入っている場合は一致しません。また、ルックアラウンドを使用しないため、かなり効率的です。質問を誤解した場合はお知らせください。

于 2013-03-01T21:31:59.493 に答える
0

@ジェイク:

ねえ、これをどうもありがとう。あなたは私が探している人です。私はそれを試してみましたが、最初の URL で動作しますが、2 番目の URL には何も出力しません。

元の正規表現を使用して、HTML::TreeBuilder で html タグを削除してみました:

my $tree = HTML::TreeBuilder->new;
$tree->parse_file($doc);
my $non_html = $tree->as_text();
open FILE, "<", \$non_html or die "can't open $non_html: $!\n";

どちらの URL でも結果はありません。

HTML::Strip を試してみました:

my $hs = HTML::Strip->new();
my $clean_text = $hs->parse($doc);
$hs->eof;
open FILE, "<", \$clean_text or die "can't open $clean_text: $!\n";

元の URL と同じ結果になります。最初の URL は期待どおりに機能し、2 番目の URL はすべての (削除された) 行を出力します。私のコードに問題があるのか​​もしれません。知らない。

これが私のスクリプトの本質です(これが実行されます):

use strict;
use warnings;
use LWP::Simple;

my $url = 'http://eclipse.gsfc.nasa.gov/phase/phases2001.html';
#my $url = 'http://www.astropixels.com/ephemeris/moon/phases2001gmt.html';
my $doc = get $url;
die "Couldn't get $url" unless defined $doc;
open FILE, "<", \$doc or die "can't open $doc: $!\n";

while(my $line = <FILE>)
{
    #next unless $line =~ /^(?=.*?\bYear\b)(?=.*?\bNew Moon\b)(?=.*?\bFirst Quarter\b)(?=.*?\bFull Moon\b)(?=.*?\bLast Quarter\b).*$/gim; # original
    next unless $line =~ /^(?:\s*<[^>]*?>\s*)*\s*Year\s*New Moon\s*First Quarter\s*Full Moon\s*Last Quarter\s*(?:\s*<[^>]*?>\s*)*$/gim; # Jake's
    print "$line";
}
于 2013-03-02T16:39:44.933 に答える
0

取得したhtmlドキュメントを直接ループすることで、元の正規表現を使用して両方のURLでこれが機能するようになりました。

for my $line (split qr/\R/, $doc)
{
    next unless $line =~ /^(?=.*?\bYear\b)(?=.*?\bNew Moon\b)(?=.*?\bFirst Quarter\b)(?=.*?\bFull Moon\b)(?=.*?\bLast Quarter\b).*$/gim; # original
    print "$line\n";
}

それほど難しいことではないはずです。;-)

于 2013-03-02T06:32:35.100 に答える