PHPでWebへのリンクがあったら、正規表現で<a>タグを生成する。 | φ(..)メモとして残しておこう…

PHPでWebへのリンクがあったら、正規表現で<a>タグを生成する。


http://~で始まる文字列を自動的にリンクに変えたい。



文字列にURLが入ってる場合には、その文字列全体を<a>タグで囲んで<li>タグに入れる…というのをしたいと思います。

jQuery-Mobileでリストにリンクを貼りたい時なんかに使います。

1/15に書いたエントリーで、TwitterのAPIを使って文字列を取得してくるというのをやったわけですが、この文字列の中に「http://…」で始まる文字列があった場合には、その文字列全体をリンクで囲みたい、と。

URLが文字列の中に入っているかどうかは、正規表現で調べます。

今回使う正規表現のURLパターンはこんな感じです。
/http:\/\/[0-9a-z_,.:;&=+*%$#!?@()~\'\/-]+/i


前回やったTwiitterのAPIを使ってユーザーのツイートを取得してくるコードは、以下のように変更出来ます。


//Tweetを取得するためのURLを設定
$url = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=ikuzo1930&page=" . $_POST['page'];

//file_get_contents()で取得したJSONコードをjson_decodeでデコード
$tweet = json_decode(file_get_contents($url));


foreach ($tweet as $val){

// 文字列を$strに入れる
$str = $val->text;

// URLの正規表現パターンを設定
$pattern = '/http:\/\/[0-9a-z_,.:;&=+*%$#!?@()~\'\/-]+/i';

// 文字全体を<a>タグで囲んじゃう。
$replace = '<a href="$0" data-ajax="false">' . $str . '</a>';

//preg_macth()でURLが含まれているか調べて置き換え。
//URLが存在する場合は置き換えるんだけど$strが重複するのでtrim()

$replaced = ( preg_match($pattern, $str) <> 0 )? trim( preg_replace($pattern, $replace, $str), $str ) : $str;

//出力
echo "<li>" . $replaced . "</li>\n";
}


だいたい、こんな感じです。


もし、文字列全体ではなくURLにリンクを貼りたい場合には、以下のように変更です。
多分…。



//Tweetを取得するためのURLを設定
$url = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=ikuzo1930&page=" . $_POST['page'];

//file_get_contents()で取得したJSONコードをjson_decodeでデコード
$tweet = json_decode(file_get_contents($url));


foreach ($tweet as $val){

// 文字列を$strに入れる
$str = $val->text;

// URLの正規表現パターンを設定
$pattern = '/http:\/\/[0-9a-z_,.:;&=+*%$#!?@()~\'\/-]+/i';

// 文字全体を<a>タグで囲んじゃう。
$replace = '<a href="$0">$0</a>';

//preg_macth()でURLが含まれているか調べて置き換え。
$replaced = preg_replace($pattern, $replace, $str);

//出力
echo "<li>" . $replaced . "</li>\n";
}


もし、文字列にURLが入っていたらリンクを自動生成するなんて時には使えるかもしれません。


以下は、自分用メモ。

メールアドレスのパターン
/^[-._a-zA-Z0-9\/]+@[-._a-z0-9]+\.[a-z]{2,4}$/

URLパターン
/^(?:http|https):\/\/[\w,.:;&=+*%$#!?@()~\'\/-]+$/

電話番号
/^0\d{1,4}[-(]?\d{1,4}[-)]?\d{3,4}$/

マルチバイト文字の正規表現パターン
"全角カタカナ" + "スペース" だけで構成されてるかをチェックするパターン
^[ ァ-ヶー]+$

"全角ひらがな" + "スペース" だけで構成されてるかをチェックするパターン
^[ ぁ-んー]+$

半角カナが含まれているかチェックするパターン
[。-゚]




…と。
まあ、色々と正規表現をメモしているわけですが

詳説 正規表現 第3版

新品価格
¥5,040から
(2012/1/17 11:14時点)




こんなのとかあるぐらいですから、正規表現は難しいです。
高え…。
オライリーの本の中でも、高い方の部類に入るんじゃないかな…?

「PHP使いはもう正規表現をblogに書くな」と言わせないでくれ
弾さんのこんなエントリーもあるくらいなので、一朝一夕には理解も使いこなすことも出来ないのが正規表現の奥深さです。

まあ、僕はPHPerとして「ブログに正規表現を書いてしまった」わけですが…。

実際に今回書いたURLのマッチパターンですが、「日本語ドメイン」(お名前.comにたいなやつね)にはマッチしませんし、パラメータ付きのURLにもマッチしません。

たとえば、パラメータ付きのURLの場合だと
/(http|https):\/\/([-._a-z\d]+\.[a-z]{2,4})([\w,.:;&=+*%$#!@()~\'\/-]*)\??([\w,.:;&=+*%$#!?@()~\'\/-]*)/
こんな感じにも書けたりするみたいですが…。


$pattern = '/(http|https):\/\/([-._a-z\d]+\.[a-z]{2,4})([\w,.:;&=+*%$#!@()~\'\/-]*)\??([\w,.:;&=+*%$#!?@()~\'\/-]*)/';

$str = 'http://www.example.com/none/index.php?param=0123&data=999';

$match = array();

preg_match($pattern, $str, $match);
var_export($match);

上記の出力結果

array (
0 => 'http://www.example.com/none/index.php?param=0123&data=999',
1 => 'http',
2 => 'www.example.com',
3 => '/none/index.php',
4 => 'param=0123&data=999',
)



無駄に正規表現を使うよりもparse_url()を使うとか、選択肢はたくさんあると思います。

$url = 'http://username:password@hostname/path?arg=value#anchor';

print_r(parse_url($url));
?>

上の例の出力は以下となります。

Array
(
[scheme] => http
[host] => hostname
[user] => username
[pass] => password
[path] => /path
[query] => arg=value
[fragment] => anchor
)


パンくずリストを自動生成するような場合とか


$list = $_SERVER['PHP_SELF'];

//区切り文字"/"で配列に入れる
$data = explode('/', $list);


こんな処理をしたりする場合もありますし。

要は使い分けなのかなーと思います。

There's more than one way to do it.
やりかたは色々あるし。