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) と参照渡しにするのを忘れないでください。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です