̃Gg[͂ĂȃubN}[Nɒlj

PHP :: 正規表現 / 「先読みの否定」を利用した例



$str = '<font color="red"><font size="3">フォントカラー赤:サイズ3</font></font>';

上記文字列から「 フォントカラー赤:サイズ3 」を抽出する場合を考える


まず、「最短マッチ」を試してみる

<?php
$str = '<font color="red"><font size="3">フォントカラー赤:サイズ3</font></font>';
preg_match('#<font\s+.*?>(.+?)</font>#', $str, $cap);
var_dump($cap);
?>

↓結果

array(2) {
  [0]=>
  string(65) "<font color="red"><font size="3">フォントカラー赤:サイズ3</font>"
  [1]=>
  string(40) "<font size="3">フォントカラー赤:サイズ3"
}

最短マッチでは意図した結果にならない


「先読みの否定」を利用

<?php
$str = '<font color="red"><font size="3">フォントカラー赤:サイズ3</font></font>';
preg_match('#<font\s+.*?>((?!<font\s+.*?>).*?)</font>#', $str, $cap);
var_dump($cap);
?>

↓結果

array(2) {
  [0]=>
  string(72) "<font color="red"><font size="3">フォントカラー赤:サイズ3</font></font>"
  [1]=>
  string(25) "フォントカラー赤:サイズ3"
}


でも、完璧ではなかった。。

$str = '<font color="red">ほげほげ<font size="3">フォントカラー赤:サイズ3</font></font>';

のように fontの開始タグの間に「ほげほげ」とあった場合。下記の結果になってしまう。

array(2) {
  [0]=>
  string(73) "<font color="red">ほげほげ<font size="3">フォントカラー赤:サイズ3</font>"
  [1]=>
  string(48) "ほげほげ<font size="3">フォントカラー赤:サイズ3"
}


「先読みの否定」を利用 (完璧バージョン)

<?php
$str = '<font color="red">ほげほげ<font size="3">フォントカラー赤:サイズ3</font></font>';
preg_match('#<font\s+.*?>((?!.*<font\s+.*?>).*?)</font>#', $str, $cap);
var_dump($cap);
?>

↓結果

array(2) {
  [0]=>
  string(73) "<font color="red">ほげほげ<font size="3">フォントカラー赤:サイズ3</font>"
  [1]=>
  string(25) "フォントカラー赤:サイズ3"
}

これで望み通りの結果になる。


ポイント

preg_match('#<font\s+.*?>((?!.*<font\s+.*?>).*?)</font>#', $str, $cap);
                             ^^
                             「.*」を入れて、0文字以上の任意の文字列を許可するのがポイント



programming/php/regex/look-ahead_negation.txt