正規表現で画像ファイルのURLを取り出す

(1/1)
前々回、テキストから URL を取り出す正規表現を紹介したが、今回は、ネット上のコンテンツから <img> タグで指定された画像 URL を取り出すプログラムを作ってみることにする。正規表現を少し変更するだけで、音声や動画ファイルの URL を取り出すこともできる。

サンプル・プログラム

<img src=~> の表現形式

<img> タグの src 部分の URL 指定は、前々回で紹介した「URL で使える文字」の通りだが、相対指定――'http://' ではじまらない――があることに留意する必要がある。
また、拡張子は画像限定なので、jpg, jpeg, gif, png, bmp の 5種類を対象とすることにする。これを正規表現で表すと以下のようになる。

/\<img(.*)src=\"?([\-_\.\!\~\*\'\(\)a-z0-9\;\/\?\:@&=\+\$\,\%\#]+(jpg|jpeg|gif|png|bmp))/i


拡張子指定を変更することで、音声や動画ファイルの URL を取り出すこともできる。こうしたカスタマイズのしやすさも、正規表現の強みである。
また、詳しいことはプログラムの説明で述べるが、今回は preg 系の正規表現関数を使うため、パターン全体をスラッシュ '/' で囲む必要がある。

今回使った正規表現

( )
サブパターン。 マッチングだけであれば不要だが、置換を行うために、マッチした部分文字列に番号を付けてやる必要がある。その場合にサブパターンを用いる。
-
文字の範囲指定。 a-z はアルファベット小文字すべてに、0-9は数字すべてにマッチする。
{a,b}
直前文字の a 回以上 b 回以下の繰り返し。bは省略できる。 年は4桁以下、月と日は2桁以下の数字になるので、これを用いた。
?
直前1文字の0または1回の繰り返し。
+
直前1文字の1回以上の繰り返し。
(a|b)
aまたはbにマッチする。
i
修飾子。パターンの中の文字は大文字にも小文字にもマッチする。
ここでは、文字クラス '[a-z]' に対応するアルファベット大文字や、サブクラス '(jpg|jpeg|gif|png|bmp)' に対応する大文字の拡張子にもマッチする。

サンプル・プログラムの解説:正規表現

0022: // 取り出すパターン
0023: define('REGPAT', '/\<img([^\>]*)src=\"?([\-_\.\!\~\*\'\(\)a-z0-9\;\/\?\:@&=\+\$\,\%\#]+(jpg|jpeg|gif|png|bmp))/i');

正規表現は、あらかじめ定数 REGPAT に格納しておく。この値を変更することで、コンテンツの中からさまざまな部分文字列を取り出すことができる。

サンプル・プログラムの解説:画像URL抽出

0081: /**
0082:  * テキスト中から画像URLを取り出す
0083:  * @param string $str 解析するテキスト
0084:  * @param array  $imgs 複数のURLを格納した配列
0085:  * @return int マッチしたURL数 / FALSE(抽出に失敗)
0086: */
0087: function get_url($str, &$imgs) {
0088:     //マッチするすべての部分文字列を取り出す
0089:     if (($n = preg_match_all(REGPAT, $str$arrPREG_SET_ORDER)) == FALSE)
0090:         return FALSE;
0091: 
0092:     //1次元配列にコピーする
0093:     foreach ($arr as $key=>$val)    $imgs[$key] = $arr[$key][2];
0094: 
0095:     return $n;
0096: }

実際に URL 取り出しを行うのは、ユーザー定義関数 get_url である。

まず、 preg_match_all  関数で、REGPAT にマッチする部分文字列を取り出す。
ereg 系関数が POSIX 互換の正規表現であったのに対し、preg 系関数は Perl 互換の正規表現を指定する。
今回は、入力テキストに複数の URL が含まれている場合があるが、ereg 系関数では複数の部分文字列を取り出せるような関数が用意されていない。もちろん、ユーザー定義すればできるが、大文字・小文字の場合分けなどが必要で処理が複雑になるため、一気に複数の取り出しができる  preg_match_all  関数を使うことにした。

 preg_match_all  関数の戻り値は 2 次元配列になる。REGPAT では 2番目のサブパターンに画像ファイルを含む URL がマッチするようにつくってあるので、1 次元配列 $imgs にコピーするようにした。
'<img src=~>' で指定される URL では、相対指定である('http://' ではじまらない)場合がある。このままでも構わないのだが、最初にコンテンツの URL を入力しているので、これから絶対アドレスを計算することができる。URL を絶対パスに正規化するために、「PHP でリンク切れを調べる」で作ったユーザー関数 reg_urls を流用した。

質疑応答

【質問】

「正規表現で画像ファイルの URL を取り出す」を今作成している PHP プログラム(普通のリンクを取り出すプログラムです)の参考にしたいので、動作確認のため、プログラムを自分のPCにダウンロードして実行しましたが、正常に動作しませんでした。
しばらくレスポンスが帰ってこない状態が続いた後、ブラウザが空白になってしまうのです。何のエラー表示もありません。原因に心当たりがあったら、教えて頂けないでしょうか。
PHP のバージョンは 5.3.0 です。よろしくお願いします。


【回答】

PHP 5.3 は、従来の PHP 5.x シリーズから大幅な仕様変更が行われ、本プログラムで使っていた関数  split  が非推奨となりました。このための不具合と思われます。
そこで、関数  preg_split  で代替したバージョン 1.3 を作ってみました。新しいプログラムをダウンロードしてお試しください。

(この項おわり)
header