2

我正面临 Perl 正则表达式的问题。在一个img元素上,我想将src属性与以 开头的值匹配/file?id,并与任何classalt属性匹配。我想忽略rel有时存在有时不存在的属性,如下所示:

<img rel="lightbox[45451]" src="/file?id=13166" class="bbc_img" alt="myimagess.jpg">    

<img  src="/file?id=13166" class="bbc_img" alt="myimagess.jpg">

我的问题是如何处理可选rel属性。

我正在尝试这个rel属性匹配:

(?!\s+(rel)="([^"]+)")

它在没有属性时有效,但在有rel属性时失败。imgrel

4

3 回答 3

2

使用适当的 HTML 解析器很容易做到这一点。本程序演示使用HTML::TreeBuilderlook_down方法。

它正在搜索所有元素:

  • 'img' 的标签名称
  • 匹配正则表达式 qr|^/file\?id=|的src属性
  • 匹配空正则表达式的class属性(即具有任何值的类属性)
  • 与空正则表达式匹配的alt属性

找到元素后,您不会说要对它们做什么。此代码仅用于as_HTML显示它们。

use strict;
use warnings;

use HTML::TreeBuilder;

my $html = HTML::TreeBuilder::XPath->new_from_file(\*DATA);
my @images = $html->look_down(
  _tag => 'img',
  src => qr|^/file\?id=|,
  class => qr//,
  alt => qr//
);
print $_->as_HTML, "\n" for @images;

__DATA__
<html>
  <head>
    <title>Page title</title>
  </head.
  <body>
    <img rel="lightbox[45451]" src="/file?id=13166" class="bbc_img" alt="myimagess.jpg">    
    <img  src="/file?id=13166" class="bbc_img" alt="myimagess.jpg">
    <img  src="/file" class="bbc_img" alt="myimagess.jpg"> /* mismatch id="" */
    <img  src="/file?id=13166" alt="myimagess.jpg">        /* no class="" */
    <img  src="/file?id=13166" class="bbc_img">            /* no alt="" */
  </body>
</html>

输出

<img alt="myimagess.jpg" class="bbc_img" rel="lightbox[45451]" src="/file?id=13166" />
<img alt="myimagess.jpg" class="bbc_img" src="/file?id=13166" />
于 2013-07-19T08:51:33.153 回答
2

Web::Query获胜!

use Web::Query 'wq';
my $html = <<'';
<html>
<img rel="lightbox[45451]" src="/file?id=13166" class="bbc_img" alt="myimagess1.jpg">
<img class="bbc_img" src="/file?id=13167" alt="myimagess2.jpg">
<img src="/file?id=13168" class="bbc_img" >
<img src="/file?id=13169" alt="myimagess3.jpg">
<img  src="/foo" class="bbc_img" alt="myimagess.jpg4">

print for wq($html)->find('img[src^="/file?id="][class][alt]')->attr('src');
__END__
/file?id=13166
/file?id=13167

从中吸取教训:XPath 比 CSS 选择器更强大,但 CSS 选择器更短。

于 2013-07-19T09:55:23.000 回答
1

使用HTML::TreeBuilder::XPath的正确方法。这将忽略rel和任何其他属性,以及不依赖于标签中属性的顺序。

#!/usr/bin/perl

use strict;
use warnings;

use HTML::TreeBuilder::XPath;
use Test::More tests => 1;

my $root= HTML::TreeBuilder::XPath->new_from_content( do { local undef $/; <DATA> });

# this is the important part 
my @imgs= $root->findnodes( '//img[starts-with( @src,"/file?id=") and @class and @alt]');

# checks the results
my $hits= join ' ', map { "H:" . src_id( $_->{src}) } @imgs;
is( $hits, 'H:13166 H:13167', "one test");

# shows how to access the attributes
foreach my $img (@imgs)
  { warn "hit: src= $img->{src} - class=$img->{class} - alt: $img->{alt} - id= ", src_id( $img->{src}), "\n"; }

exit; 

sub src_id
  { my( $src)= @_;
    return $src=~  m{/file\?id=(.+)$} ? $1 : 'no id'; 
  }

__DATA__
<html>
  <head><title>Test HTML</title></head.
  <body>
    <img rel="lightbox[45451]" src="/file?id=13166" class="bbc_img" alt="myimagess1.jpg">
    <img class="bbc_img" src="/file?id=13167" alt="myimagess2.jpg">
    <img src="/file?id=13168" class="bbc_img" >
    <img src="/file?id=13169" alt="myimagess3.jpg">
    <img  src="/foo" class="bbc_img" alt="myimagess.jpg4">
  </body>
</html>
于 2013-07-19T08:15:43.863 回答