2013-07-19 14 views
2

我正面臨一個Perl正則表達式的問題。在img元素上,我想匹配src屬性的值,該值以/file?id開頭,並與classalt屬性匹配。我想忽略rel屬性有時存在,有時並不像下面存在:正則表達式匹配`img`元素的`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屬性失敗。

+7

[不要這樣做](http://stackoverflow.com/a/1732454/19068),使用一個真正的[HTML解析器](https://metacpan.org/module/HTML::TreeBuilder :: XPath)。 – Quentin

+0

一月:你的意思是(二)學習如何*不*正則表達式。 – innaM

+1

@Quentin使用正則表達式來匹配一個已知的,有限的HTML/XML子集可以很好,這取決於所需的穩健性水平與複雜性和性能水平。當你知道爲什麼和後果是什麼時,也可以打破規則。 –

回答

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> 
2

這是使用正確的HTML解析器做的微不足道。該程序演示使用HTML::TreeBuilderlook_down方法。

它搜索與所有元素:

  • 'IMG' 的標籤名
  • 的正則表達式匹配QR一個src屬性|^/文件\ 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選擇器更短。

+0

表示同意,雖然我在等待強制性的XSH2解決方案來贏得冠軍; - ) – mirod

相關問題