preg_replace_callbackでマッチごとに処理する
preg_replace_callback とは、正規表現にマッチするたびにコールバックを呼び、その戻り値で置換する関数です。置換内容を動的に計算したいときに使います。
置換後の値を計算したいとき
単純な置換なら preg_replace で足りますが、「マッチした内容に応じて置換文字列を変えたい」ときは preg_replace_callback の出番です。マッチするたびにコールバックが呼ばれ、その戻り値が置換結果になります。数式の評価や、動的な整形に効きます。
$text = '価格は 1200 と 350 です';
$result = preg_replace_callback(
'/\d+/',
fn($m) => number_format((int)$m[0]),
$text
);
// "価格は 1,200 と 350 です"
コールバックの引数 $m にはマッチ結果の配列が渡ってきます。$m[0] が全体、$m[1] 以降がキャプチャグループですね。
キャプチャグループを使った加工
グループを使えば、マッチの一部だけを取り出して加工できます。たとえばマークダウン風の記法をタグに変換したり、テンプレート変数を値に差し替えたり、といった処理が書きやすくなります。
$md = '**強調**と普通のテキスト';
$html = preg_replace_callback(
'/\*\*(.+?)\*\*/',
fn($m) => '<strong>' . htmlspecialchars($m[1]) . '</strong>',
$md
);
// "<strong>強調</strong>と普通のテキスト"
置換文字列内でエスケープ処理を挟めるのが、単純な preg_replace にはない強みだと思います。
状態を持たせる、複数パターンをさばく
コールバックはクロージャなので、use で外の変数を取り込めます。これを使うと「何番目のマッチか」を数えたり、辞書を引いて置換したりできます。連番を振る処理などで重宝します。
$dict = ['cat' => '猫', 'dog' => '犬'];
$out = preg_replace_callback(
'/\b(cat|dog)\b/',
fn($m) => $dict[$m[1]] ?? $m[0],
'a cat and a dog'
);
// "a 猫 and a 犬"
// カウンタを持たせて連番を振る
$n = 0;
$numbered = preg_replace_callback(
'/^- /m',
function ($m) use (&$n) {
$n++;
return "{$n}. ";
},
"- りんご\n- みかん"
);
カウンタを変えたいときは use (&$n) と参照渡しにするのを忘れないようにしたいですね。ここは私もよく付け忘れます。
まとめ
preg_replace_callback は「マッチした値をもとに置換内容を計算する」ための道具で、数値整形・記法変換・辞書引きなど応用範囲が広いです。$m[0] が全体で $m[1] 以降がグループという受け取り方と、use による状態の持ち込みを押さえておけば、単純な置換では届かない加工が素直に書けると思います。
よくある質問
Q. preg_replace との使い分けは?
A. 単純な置換なら preg_replace、マッチした内容に応じて置換文字列を計算したいなら preg_replace_callback です。
Q. コールバックの引数には何が渡りますか?
A. マッチ結果の配列 $m が渡ります。$m[0] が全体、$m[1] 以降がキャプチャグループです。
Q. 置換のたびにカウンタを増やしたいです。
A. クロージャの use で外の変数を取り込みます。値を書き換えるなら use (&$n) と参照渡しにするのを忘れないでください。