PHP の正規表現パーサーは欲張り?!
PHP の正規表現パーサーは、欲張り (貪欲) です。英語で Greedy である、といいます。
これはどういうことかというと、「なるべく多くの文字をマッチさせる」 ということです。
具体的な例で見てみましょう。
例えば、ある文字列中の <b> から始まって、</b> で終わる部分をマッチさせたいと思い、 次のような青字のパターンを書いたとします。
$t = '<b>これはテスト</b>です。<b>これもテスト</b>です。';
preg_match_all('@<b>.*</b>@', $t, $matches);
foreach($matches[0] as $m) {
echo htmlentities($m,ENT_QUOTES,"UTF-8") . '<br>';
}
すると、$t にセットされた文字列の一番外側の <b> と </b> に囲まれる箇所がマッチして、 preg_match_all でマッチする結果は次の通りになります。
<b>これはテスト</b>です。<b>これもテスト</b>
このように、<b> から始まって、</b> で終わる箇所の最長箇所がマッチしています。
さて、この greedy なマッチをさせずに、短い箇所にマッチさせるためにはどうしたらよいでしょうか? 上の例で言えば、「これはテスト」という箇所と「これもテスト」 という箇所の二箇所をマッチさせるにはどうしたら良いでしょうか。
それには、実は次のように ? をつければ OK です。
$t = '<b>これはテスト</b>です。<b>これもテスト</b>です。';
preg_match_all('@<b>.*?</b>@', $t, $matches);
foreach($matches[0] as $m) {
echo htmlentities($m,ENT_QUOTES,"UTF-8") . '<br>';
}
この結果は、意図したとおり <b> と </b> に囲まれた二箇所の部分がマッチします。
<b>これはテスト</b> <b>これもテスト</b>