【问题标题】:Regex to match `rel` attribute of `img` element which only exists sometimes正则表达式匹配“img”元素的“rel”属性,该属性有时仅存在
【发布时间】:2013-07-19 07:45:24
【问题描述】:

我遇到了 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 属性时它会失败。

【问题讨论】:

  • Don't do that,请改用真实的HTML parser
  • @Quentin 使用正则表达式来匹配已知的、有限的 HTML/XML 子集可能很好,具体取决于所需的稳健性与复杂性和性能级别。也就是当你知道为什么和后果是什么时,打破规则是可以的。
  • @January:不是真的。使用现成的解析器几乎总是比使用正则表达式更快且更少脏。而 HTML 不是正则表达式的不良目标,正如这个问题所表明的那样,并且会误导学习者。
  • @January:我完全不同意。正则表达式不可能比为域编写的解析器“更持久”。特别是,这项任务非常复杂,需要非常全面的测试,而且永远无法确认它是正确的。通过为不打算处理的数据编写代码来学习语言并不是一个好方法。 HTML 不是常规语言,您永远无法使用正则表达式编写完整的通用 HTML 处理解决方案。您不妨提倡在 Logo 中编写客户端脚本。
  • @January:不。使用正则表达式处理不规则语言是一个坏主意。请不要宣传你的错误想法。

标签: regex perl


【解决方案1】:

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

它正在搜索所有元素:

  • 标签名“img”
  • src 属性匹配正则表达式 qr|^/file\?id=|
  • 与空正则表达式匹配的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" />

【讨论】:

    【解决方案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 选择器更短。

    【讨论】:

    • 同意,尽管我正在等待强制性 XSH2 解决方案来为获胜者加冕;--)
    【解决方案3】:

    使用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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 2010-12-22
      • 1970-01-01
      相关资源
      最近更新 更多