0

正则表达式的混合结果,匹配 html 代码中的短语列表

这篇新帖子是对另一篇帖子的回应,Perl Regex match lines that contains multiple words,但由于我不知道的原因被版主删除了。在原始线程中问这个问题对我来说似乎是合乎逻辑的,因为它与尝试使用该线程早期给出的解决方案以及它的问题有关。有一个对faq的通用引用,它似乎没有显示任何差异,以及消息,“如果您有问题,请发布您自己的问题。” 因此这篇文章。

我正在使用 LWP::Simple 获取网页,然后尝试匹配包含某些短语的行。我在上述线程中的答案#1中复制了正则表达式,并替换/添加了我需要匹配的单词,但是我得到的结果与两个相似但不同的网页混合在一起。

我正在使用的正则表达式是:

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

对于网站#1,它有包含这些单词的裸行,在一系列由<pre>..</pre>标签包围的块中,它匹配所有与该行完全相同的行,如预期的那样:

 Year        New Moon       First Quarter       Full Moon       Last Quarter

但是对于网站#2,它的单词周围有令人讨厌的小标签:

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

它匹配每一行!

我确定<span>标签是执行此操作的“正确”方式,但我想知道如何绕过这些标签,以便我可以为两个站点只使用一个正则表达式。有没有一种简单的方法可以做到这一点,还是我必须学习如何解析 html(我不想这样做)?

我正在寻找一种快速的解决方案,而不是一个强大的解决方案。这可能是一次性的交易。如果这些相对静态的页面发生变化,它可能会很小并且很容易修复。请不要向我介绍所有“反正则表达式换html”页面。我见过他们。请不要让我使用 HTML::TreeBuilder。哦拜托...

4

3 回答 3

0

如果我的假设是正确的,您只想匹配特定的单词序列:

Year        New Moon       First Quarter       Full Moon       Last Quarter

无论末端的标签如何,都有自由间距。

我们可以使用它来匹配两端任何格式正确的开始和结束标签

<[^>]*?>

这意味着,任何介于开头“<”和第一个结尾“>”之间的字符串,

接下来我们要确保我们允许这些标签之间有空格,所以我们使用空格指示符“\s*”来表示两端的零个或多个空格:

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

接下来,我们要将其分组到一个非捕获(为了提高效率)组中,并让它重复零次或多次。这是我们将放在正则表达式两端以确保标签匹配的内容:

(?:\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

通过直接遍历检索到的 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 回答
0

@杰克:

嘿,非常感谢。你就是我要找的人。我试过了,它适用于第一个 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";

两个网址都没有结果。

我试过 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 按预期工作,第二个输出所有(剥离)行。也许我的代码在这里有问题。我不知道。

这是我的脚本的本质(运行):

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 回答