RSSから画像の取り込みで正規表現がわかりません preg_match - PHPプロ!Q&A掲示板

1544

  • 300P

RSSから画像の取り込みで正規表現がわかりません preg_match

質問日時 / 2008年10月9日 02:52 (最終編集:10月9日 22:29)    回答数 / 12件

Questioner:  yumisaiki  このエントリーをはてなブックマークに追加 

キーワード / 正規表現   

http://www.phppro.jp/qa/detail.php?id=379
で教えていただいた、ブログの記事を取得するのは本当に便利に使っています。

 で、ぶろぐん も加工をほどこして、これでいつも使っています。

 http://池田久美.jp/
 が使用中の例です。本当にありがとうございます。

 で、この画面に、せっかくのお人形さんの可愛い写真をできたらランダムで表示できるようにしたいなと思い、
 さっそく加工に挑戦しようと思ったのですが、さっそく正規表現でつまづいています。
 いくらやっても/が多いというエラーになります。

 http://ikekumi.lovepop.jp/bg/?mode=rss&c=3-2
 の写真を取得したいのです。
 例えば

<img src="http://ikekumi.lovepop.jp/bg/files/20080521143814.JPG" width="320" height="240" alt="" />

 を表示させたいのです。

 で、とりあえず以下のようなものを作ってみました。
  1. <?php 
  2. // RSS番号  
  3. $num = $_GET["rssno"]
  4. // URLの指定 
  5. $rdf_url = "http://ikekumi.lovepop.jp/bg/?mode=rss&c=".$num;
  6.   
  7. // RSSを取得 
  8. $content = file_get_contents($rdf_url)
  9.   
  10.  
  11.   
  12. // rdfを解析する (下の関数で処理) 
  13. $datas = analyze_rdf($content)
  14.   
  15.  
  16. // rdf ファイルを解析するための関数 
  17. function analyze_rdf($cnt) { 
  18.     // <item> ~ </item> を切り出す 
  19.     $ptn = '/<item[^>]*>(.+)<\/item>/sU'
  20.     preg_match_all($ptn$cnt$matches)
  21.   
  22.     // マッチしてれば 
  23.     if (count($matches) > 0) { 
  24.         // 配列に入れる 
  25.         $items = $matches[1]
  26.     } else { 
  27.         return FALSE
  28.     } 
  29.     
  30.     // パターンの指定  
  31.     
  32.     $ptns["img"] = '/<img[\s\t]+src[\s\t]*=[\s\t]*"http://ikekumi\.lovepop\.jp\/bg\/files\/\d+\.jpg)"[^\/>]*?\?>/sU'
  33.     $ptns["link"] =  '/<link>(.*)<\/link>/sU';  
  34.     $ptns["title"] = '/<title>(.*)<\/title>/sU'
  35.     $return_array = array()
  36.   
  37.    
  38.     // link の抜き出し 
  39.     foreach ($items as $val) { 
  40.         $res = array()
  41.   
  42.       preg_match($ptns["img"]$val$matches)
  43.         $res["img"] = $matches[1]
  44.         preg_match($ptns["link"]$val$matches)
  45.         $res["link"] = $matches[1]
  46.         preg_match($ptns["title"]$val$matches)
  47.         $res["title"] = $matches[1]
  48.   
  49.         $return_array[] = $res
  50.      
  51.     } 
  52.   
  53.     // 配列を返す 
  54.     return $return_array
  55. } 
  56.  
  57.     // $count 個分の配列を生成 
  58.     for ($i = 0$i < $count$i++) { 
  59.         $tmp_array[] = $i
  60.     } 
  61.   
  62.   
  63. // HTML に整形するための関数 
  64.  
  65. function make_html($data) { 
  66.     $str = "<a target=\"_parent\" href=\"" . $data["link"] . "\">"
  67.     $str .= $data["title"]."</a><br/>".$data["img"];
  68.     return $str
  69. } 
  70.  
  71. print make_html($datas[0]);
  72.  
  73. ?>

と書いてやってみましたが、
http://ikekumi.lovepop.jp/blog2.php
 のようなエラーになります。 

<img src="http://ikekumi.lovepop.jp/bg/files/20080521143814.JPG" width="320" height="240" alt="" />
のパターンは、

'/<img[\s\t]+src[\s\t]*=[\s\t]*"http://ikekumi\.lovepop\.jp\/bg\/files\/\d+\.jpg)"[^\/>]*?\?>/sU'
ではないのでしょうか?

 正規表現って簡単なようで難しいですね。
 どこか勉強するのにオススメの本やサイトがあったら教えてほしいです。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┗A01tezcello 「いくらやっても/が多いというエラーになります。
 ┗A01-1yumisaiki早速にありがとうございます。 $ptns["img"] = '/<
  ┗A01-1-1mgngmgng> unmatched parentheses 閉じ括弧 ) はあります
   ┗A01-1-1-1yumisaiki単純に)を抜いたらエラーは消えたのですが、 やはり
    ┣A01-1-1-1-1mgngmgng> どうして)を書いたのか??? $matches[1]にキャ
    ┃┗A01-1-1-1-1-1yumisaikiリンク先ありがとうございます。とてもやる気が出てき
    ┗A01-1-1-1-2tezcelloデリミタは、パターンの最初と最後のしるしの事で、ht
     ┗A01-1-1-1-2-1yumisaiki教えていただいたのを見て 再度考えて、 えーいと。
      ┗A01-1-1-1-2-1-1tezcelloこれは、i 修飾子と呼ばれるもので、「大文字小文字を
       ┗A01-1-1-1-2-1-1-1yumisaikiそうなんですか。 なぜか 何も表示しなかったんです
        ┗A01-1-1-1-2-1-1-1-1tezcelloあっ、ごめんなさい。 変なとこでミスしてたんですね
         ┗A01-1-1-1-2-1-1-1-1-1yumisaikiなんとなく感覚で使っているので、とても参考になりま

回答一覧

並び替え:

A01 参考になった
answerertezcello [10月9日 08:14]


「いくらやっても/が多いというエラーになります。」とパターン文字列からすると
http のうしろの // が引っかかるのだろうと思います。
デリミタはスラッシュでなくても良いので、url を扱うときなどは他の文字にする事をお勧めします。
(たとえばパイプ「|」などいかがでしょう)
  参考: http://jp.php.net/manual/ja/intro.pcre.php
途中のエスケープ用の¥が無いだけでも読みやすく間違えにくくなりますよ。

この意見に回答する

ツリーへ TOPへ

A01-1
replyeryumisaiki [10月9日 12:46] (最終編集:10月9日 12:46)

早速にありがとうございます。

$ptns["img"] = '/<img[\s\t]+src[\s\t]*=[\s\t]*"http:||ikekumi\.lovepop\.jp\/bg\/files\/\d+\.jpg)"[^\/>]*?\?>/sU';

にしてみましたら、unmatched parentheses
というエラーで、たぶん正規表現が間違っていると思います。
||でいいというのはびっくりしました。 

すみません。教えていただいたリンク先に行って読んでも今ひとつ難しくて頭がついていきませんでした。

正規表現って流派がある?のでしょうか。いろんな書き方もできるようですし。
今はひとつひとつ体で覚えていってる感じです。

この意見に回答する

ツリーへ TOPへ

A01-1-1 参考になった
replyermgngmgng [10月9日 15:49]

> unmatched parentheses

閉じ括弧
)
はありますが、

始まりの括弧
(
がないですね。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1
replyeryumisaiki [10月9日 16:42] (最終編集:10月9日 16:47)

単純に)を抜いたらエラーは消えたのですが、
やはり表示されません。

どうして)を書いたのか???


 '/<img[\s\t]+src[\s\t]*=[\s\t]*"http:||ikekumi\.lovepop\.jp\/bg\/files\/\d+\.(jpg|JPG)"[^\/>]*?\?>/sU'; 

とか、思いなおして書いたらエラー消えましたが。

 申し訳ないです。 マッチしてないから出てないってことなんですよね。
 

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-1 満足
replyermgngmgng [10月9日 17:48]

> どうして)を書いたのか???
$matches[1]にキャプチャしたかったからでしょうね。多分。
詳しくは、http://jp.php.net/preg_match の「パラメータ」の部分を参照してください。

自分も正規表現は苦手なのでたいしたこといえないですが、

とりあえず
http:||ikekumi...
というパターンのURLは聞いたことないので
http:\/\/ikekumi...
に直して、

最後のほうにある
[^\/>]*?\?>
っていうのも意味がわからないので
.+\/>
くらいの簡単なものにしてみると
何かつかめるかもしれません。



> どこか勉強するのにオススメの本やサイトがあったら教えてほしいです。
このへんが参考になるかもしれません。
http://higashizm.sakura.ne.jp/reg/
http://www.kt.rim.or.jp/~kbk/regex/regex.html

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-1-1
replyeryumisaiki [10月9日 19:02]

リンク先ありがとうございます。とてもやる気が出てきました。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2 満足
replyertezcello [10月9日 17:54]

デリミタは、パターンの最初と最後のしるしの事で、http: の後ろの文字ではないです。
例示のパターンでしたら、
'!<img[\s\t]+src[\s\t]*=[\s\t]*"http://ikekumi\.lovepop\.jp/bg/files/\d+\.(jpg|JPG)"[^\/>]*?\?>!sU';
という事です。

ところで、最後の \? って必要ですか? img タグの終わりに ? はないと思います。
大文字小文字両用にするなら、i 修飾子の方がごちゃごちゃし難いと思います。
ピリオド(ドット)をメタ文字としては使っていないので、s 修飾子は不要と思います。
\s には、タブも含まれると思いますが?
+ * の前でマッチ文字を指示しているので、貪欲なマッチングでも問題なさそうな気がします。
(タグの閉じ括弧前の部分だけ貪欲であればいいんですよね?)

こんな感じでいかがでしょう?
'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/\d+\.ipg".+?/>!i'

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2-1
replyeryumisaiki [10月9日 19:23] (最終編集:10月9日 19:36)

教えていただいたのを見て
再度考えて、
えーいと。

 $ptns["img"] = '!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(.*).(jpg|JPG)".+?/>!i'; 
と書いてみたら、

お写真出たのですが、よぶんなものま出てしまう…。

でも、

 $ptns["img"] = '!<img[\s\t]+src[\s\t]*=[\s\t]*"http://ikekumi\.lovepop\.jp/bg/files/(.*)\.(jpg|JPG)".+?/>!sU';

と書きましたら、

なぜか?(私にとっては)20081007173025 
とだけ出たので、これでなんとかはなるかなと…。

(.*) の部分が抜き出せたということですね。 意味がもひとつわかってなくて…。

とりあえずありがとうございます。
>!i';
 ってどういう意味になるのですか?

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2-1-1 参考になった
replyertezcello [10月9日 20:18]

これは、i 修飾子と呼ばれるもので、「大文字小文字を区別しない」というおまじないです。

'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(.*).(jpg|JPG)".+?/>!i'
の、(jpg|JPG) 部分は、jpg だけでOKになるので、これと(ほぼ)同じ意味です。
'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(.*).jpg".+?/>!i'

で、これだと、(.*) の部分があれこれと色々な部分にマッチしてしまいます。
余分なものまで出て来てしまうのはそれが原因だと思います。
  ですが、s 修飾子を付けていないので、1行の範囲内でしかマッチしないのですが...
  ソースを見ていませんが、1行にたくさんの img タグがあるのかも知れませんね。

対策としては最短でマッチするように、? を付けておくべきでしょうね。
必ず何文字かあるでしょうから、* ではなく、+ の方がいいかもしれません。
'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(.+?).jpg".+?/>!i'

よく似た URL やらがでていると予定外のものまでマッチしてしまう可能性を消す為には、ピリオド(ドット)はエスケープ追加が必要です。
ただし、ピリオド以外にマッチするような場合は正しい URL では無いので、チャンと画像が表示出来るソースなら、エスケープしなくても大丈夫だとは思いますが。


僕の書いたの
'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/\d+\.ipg".+?/>!i'
に何か不都合がありましたか?勉強の為に教えて頂けたらと思います。

すでにお分かりとは思いますが、ファイル名部分を取り出したいのなら、
'!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(\d+)\.ipg".+?/>!i'
にすれば取り出す事ができると思います。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2-1-1-1
replyeryumisaiki [10月9日 20:51] (最終編集:10月9日 20:59)

そうなんですか。
なぜか 何も表示しなかったんです。

ではなくて これでも表示しました! すみません。

jpg じゃなくって ipg アイになっていたのです。今気がつきました。


私はこういう風に書いたら、

<img src="なんたら.jpg" nanndemo />

というのが抜き出せると思っていたのですが、なんたら 部分だけが切りだせるのはそういうものだと覚えないといけないのでしょうか?

もし解説してただけたらありがたいです。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2-1-1-1-1 満足
replyertezcello [10月9日 22:16]

あっ、ごめんなさい。
変なとこでミスしてたんですね。>自分

詳しくは、preg_match() のマニュアルを読んで頂くのが良いのですが...

実際に検索している部分は、
  1. preg_match($ptns["img"], $val, $matches); 
  2. $res["img"] = $matches[1];
なので、 <img src="なんたら.jpg" nanndemo /> が $val に入っているとすると

$ptns["img"] = '!<img\s+src\s*=\s*"http://ikekumi.lovepop.jp/bg/files/(\d+)\.jpg"(.+?)/>!i' なら
preg_match() が成功した場合は、
$matches[0] は、デリミタ(この例では!)に挟まれた全部(=img タグが丸ごと)
$matches[1] は、1番目の丸括弧の中身 この例では、\d+  なんたら に相当
$matches[2] は、2番目の丸括弧の中身 この例では .+?  nanndemo に相当
という事になります。

ただし、1番目の丸括弧の中は、\d+ ですから、数字が1回以上並んでいるというパターンですから英文字が入っていたりすると preg_match() は失敗しますので、上のコードはエラーの表示が出るかも知れません。
(失敗した時は、$matches[1] は未定義のはずなので、未定義の値を代入しようとしてエラーになる。このエラーは表示しないようにする事も可能)

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-2-1-1-1-1-1
replyeryumisaiki [10月9日 22:29]

なんとなく感覚で使っているので、とても参考になりました。
お陰で可愛くできました!

今後もよろしくお願いします。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
動的なURLを静的に見せる方法
 このエントリーをはてなブックマークに追加 
A
普通に考えて、mod_rewrite でしょうね。 http://www.nishishi.com/blog/2006/01/mod_rewrite_url.html...

>>続きを読む

GETのままでは検索エンジンのロボットが拾ってくれなかったためにSEO対策として有効だと言われていますね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)