preg_replace_callbackに置換回数を返すパラメータがあった

preg_replace_callbackに置換回数を返すパラメータがあった

preg_replace_callback関数には、「&$count」というパラメータがある。
countパラメータを指定した場合は、置換を行った回数がここに格納されます。」とのこと。

このパラメータに助けられた話。

やりたいこと

HTMLソースから img タグを抽出し、src 属性の変更と class 属性の変更をする
class属性が存在しない場合は新たに追加する

preg_replace_callback関数で課題に感じたこと

preg_replace_callback関数は、マッチした場合は、コールバック関数が呼び出されるが、マッチしない場合は、コールバック関数は呼び出されず、置換対象となる文字列がそのまま返される。

そのため、コールバック関数が呼び出されないと、class属性が存在しない場合に新たに追加する処理ができない。

既に設定されているclass属性にlazyを追記することしかできない。。

$modImage = preg_replace_callback('/class=[\"\']([^\s]*)[\"\']/i', function($class) {
	$class[1] .= ' lazy'; 
	return 'class="' . $class[1] . '"';
}, $modImage);

preg_replace_callback関数の挙動について

preg_replace_callback関数は、正規表現を使って、置換対象を全て検索し、コールバック関数を使用して置換を行う関数。
置換対象が2つあると、2回コールバック関数がよばれる動作となっている。

そして、返り値は、マッチした場合とマッチしない場合で違っている。
マッチした場合は、コールバック関数の結果を返し、マッチしない場合は、置換対象となる文字列がそのまま返される。

countパラメータの発見

ドキュメントを見ていると、countパラメータなるものがあり、
これを使えば、コールバック関数が呼び出されたかどうかがわかることに気づいた。

そういうことで以下のように$matchCountをチェックすることで、class属性がない場合の処理を組むことができた。

$modImage = preg_replace_callback('/class=[\"\']([^\s]*)[\"\']/i', function($class) {
	$class[1] .= ' lazy'; 
	return 'class="' . $class[1] . '"';
}, $modImage, 1, $matchCount);
// class属性がないため、class属性を追加
if (!$matchCount) {
	$modImage = preg_replace('/<img /i', '<img class="lazy" ', $modImage);
}

参考リンク

Web技術カテゴリの最新記事