1. 程式人生 > >PHP正則表示式匹配巢狀HTML標籤的方法和技巧

PHP正則表示式匹配巢狀HTML標籤的方法和技巧

轉載請註明出處:http://blog.csdn.net/donglynn/article/details/35788879

正則表示式是一個非常有用的程式設計技能。一般來說,簡單的抓取一個HTML頁面的某一條資訊,比如<title>標題</title>,是很容易實現的。但是,我們往往要抓取某一個列表頁面裡的多個重複的<div></div>塊裡的特定內容,並且<div></div>塊還有巢狀的使用,我們抓取的則是每個重複<div></div>塊裡的多個資訊。同時,網頁原始檔不同於一般的字串,其還存在大量的回車、換行和製表符,這些都造成了匹配失敗。而初學者往往無法判斷到底是哪個環節出現了問題,並且看到高度技巧化的正則表示式會感到非常沮喪,從而導致放棄問題的解決。

經過筆者多日的研究,終於摸索出以下方法和技巧,歡迎大家交流指正。

請看如下注意點和步驟:

1.注意/一定要被轉義成\/,否則會報錯

preg_match_all() [function.preg-match-all]: Unknown modifier

2.正則表示式用單引號'和/作為開始和結束的標界,比如'/reg partten/',採用這樣的寫法,正則表示式裡的雙引號"不必轉義

比如,

$partten='/<div class="goods_item"><a href="([^<>]+)" target="_blank"><img data-ks-lazyload="([^<>]+)" alt="([^<>]+)" width="" height=""\/>/';

3.需要先去除所有的換行符、製表符、回車等等,對於便於閱讀的html原始檔由於上述符號的存在會造成無法匹配。

$str=preg_replace("/[\t\n\r]+/","",$str);

4.我們感興趣的匹配資訊,通常是html元素中的屬性的值,因此要去除<>,否則只會匹配最後一條之前的全部資訊。

比如,對於$string="<div><a href=“1.jpg”></a></div><div><a href=“2.jpg”></a></div><div><a href=“3.jpg”></a></div>",

$partten='/<div><a href=“(.+)”/';的匹配結果是:1.jpg”></a></div><div><a href=“2.jpg”></a></div><div><a href=“3.jpg”></a></div>

這是因為,上述給出的正則表示式確實沒有限定匹配的範圍只是第一個超連結<a href=“1.jpg”></a>。

因此,要想匹配上述三個超連結的 href屬性,需要將上述匹配限定在<a href=“1.jpg”>裡面,方法也很簡單,將(.+)換成([^<>]+),即可。也就是說,這個匹配不包含下一個出現<>的地方,從而將匹配限定在同一個html標籤內

做到以上幾點,就可以完全無視html標籤巢狀不巢狀的問題,從而抓取到一個頁面所有的div重複塊中我們感興趣的內容,下附一例。

<?
//被匹配的html程式碼
$html='
<div class="goods">
	<a href="http://url1111" target="_blank">
		<img data-ks-lazyload="http://1111.jpg" alt="alt1111" width="" height=""/>
	</a>
</div>
<div class="goods">
	<a href="http://url2222" target="_blank">
		<img data-ks-lazyload="http://2222.jpg" alt="alt2222" width="" height=""/>
	</a>
</div>
<div class="goods">
	<a href="http://url3333" target="_blank">
		<img data-ks-lazyload="http://3333.jpg" alt="alt3333" width="" height=""/>
	</a>
</div>';

//去掉換行、製表等特殊字元,可以echo一下看看效果
$html=preg_replace("/[\t\n\r]+/","",$html);

//匹配表示式,注意兩點,一是包含在'/ /'裡面,再就是/要做轉義處理成\/
$partern='/<div class="goods"><a href="([^<>]+)" target="_blank"><img data-ks-lazyload="([^<>]+)" alt="([^<>]+)" width="" height=""\/><\/a><\/div>/';

//匹配結果
preg_match_all($partern,$html,$result); 

//列印結果
var_dump($result); 
?>

輸出結果,一共有4個子陣列,第一個子陣列是匹配到的所有的項,後面三個子陣列是我們匹配表示式裡的三個匹配項:
array(4) {
  [0]=>
  array(3) {
    [0]=>
    string(144) "<div class="goods"><a href="http://url1111" target="_blank"><img data-ks-lazyload="http://1111.jpg" alt="alt1111" width="" height=""/></a></div>"
    [1]=>
    string(144) "<div class="goods"><a href="http://url2222" target="_blank"><img data-ks-lazyload="http://2222.jpg" alt="alt2222" width="" height=""/></a></div>"
    [2]=>
    string(144) "<div class="goods"><a href="http://url3333" target="_blank"><img data-ks-lazyload="http://3333.jpg" alt="alt3333" width="" height=""/></a></div>"
  }
  [1]=>
  array(3) {
    [0]=>
    string(14) "http://url1111"
    [1]=>
    string(14) "http://url2222"
    [2]=>
    string(14) "http://url3333"
  }
  [2]=>
  array(3) {
    [0]=>
    string(15) "http://1111.jpg"
    [1]=>
    string(15) "http://2222.jpg"
    [2]=>
    string(15) "http://3333.jpg"
  }
  [3]=>
  array(3) {
    [0]=>
    string(7) "alt1111"
    [1]=>
    string(7) "alt2222"
    [2]=>
    string(7) "alt3333"
  }
}