正規表現の入門と豆知識

2007.05.18 Author: Jas

今週の課題はソケット接続であるサイトのHTMLを取り込み、そのなかから指定された部分の文字列を抜き出してくるというものでした。そこで、今日は初心者向けに正規表現の入門と豆知識を紹介したいと思います。

まず、正規表現を使って何ができるのかというと、ある決まったルールに当てはまる文字列を見つけることができます。例えば、「aで始まってeで終わる」というルールを決めると、"ae"とか、"apple"とか、"absolute"とか、ルールに当てはまるものは全部見つけることができます。このルールをさらに細かく決めていけば、自分が探している文字列を間違いなく探してもらえるというわけです。

次に、正規表現のルールを決めるときに使う記号について。
正規表現ではルールを決めるときに使う特殊な意味をもった記号のことをメタ文字と言います。

メタ文字 意味
^ 行頭に一致する
$ 行末に一致する
. 任意の一文字
* 直前文字の0回以上の繰り返し
+ 直前文字の1回以上の繰り返し
? 直前文字の0回または1回の繰り返し
{n} 直前文字のn 回の繰り返し
{n,} 直前文字のn 回以上の繰り返し
{n,m} 直前文字n 回以上、m 回以下の繰り返し

このぐらいは正規表現で検索すると、大体どこのページにも書いてあることですね。
でも、これだけの情報ではPHPのpreg_match()やpreg_replace()を使うときに困ったことになります。

例えば・・・

<html>
<head>
<tltle>ニュース</tltle>
</head>

<body>
<table><tr><td>
<a href="http://***.com/">
<img src="ad.jpg" alt="広告" border="0" width="200" height="60"></a><br><br>
<a href="http://***.co.jp/news.html">
<b><font size="+1">タイトル</font></b></a>
<br>
記事概要(新聞名)<br>
<a href="http://***.co.jp/news.html">[記事の全文へ]</a><br>
<br>
<li><a href="http://***.co.jp/related1.html">関連ニュース</a> - ○○新聞(日付)</li>
<li><a href="http://***.co.jp/related2.html">関連サイト</a> - ネット名<br><br> </li>
<li><a href="http://***.co.jp/related3.html">関連サイト</a> - ××情報部</li>
<li><a href="http://***.co.jp/related4.html">関連情報</a> - △大学「□□研究室」</li>
<br><br>
<li><a href="http://***.co.jp/map.jpg">周辺地図</a> - どこでも地図情報</li>
</td></tr></table>
</body>
</html>

こんな感じのサイトがあって、ソースの全部を$contentの中に代入し(ここでは、簡単にするために$contentに代入したタグは途中に改行がなく、一文で表記されていることにします)、ここから記事のタイトルと概要の部分だけ抜き出したいとします。

そこで、広告の後の<br><a href=から関連ニュースリンクの直前にある<li>までを抜き出せばいいと思って、下のような関数をphpで書いてみます。

preg_match("/<br><a href=.+<li>/", $content, $result);

するとマッチするのはタイトル直前にある<br>から「周辺地図」の直前にある<li>まで。<li>が5個あるのですが、この正規表現では一番最後にある<li>までマッチしてしまうのです。

それは、最長一致というルールがあるからなんです。
そのため、ルールに当てはまる一番最長の部分までがヒットしてしまうのです。

このままではいらない部分までマッチしてしまうので、最初に見つけた<li>までにマッチさせたいときはどうすればいいでしょうか?
実はさっきの正規表現で「.+」の後に「?」をつければ、最短一致になるので思った通りの部分が抜き出せるようになるのです。

preg_match("/<br><a href=.+?<li>/", $content, $result);

サンプルスクリプトの実行結果はこちら

このルールを知らずにpreg_match()やpreg_replace()で「.*」や「.+」を使うと、想像以上に長くマッチしてしまい、目的の文字列がうまく取り出せなくなるので注意しましょう。


最後にもう一つ、phpの正規表現に便利な関数を発見したので紹介しておきます。
それは、preg_quote()

この関数を使うと、文字列の中から正規表現のメタ文字をエスケープ処理してくれます。
オプションの第2引数にpregのデリミタを指定できるので、

preg_quote($str, '/');

上のように記述して、$strに文字列を代入すれば、エスケープ処理を行うことができます。

名古屋のWebシステム開発・ネットワーク構築会社 コネクティボへ