正規表現の名前付きキャプチャで可読性を上げる

名前付きキャプチャとは、正規表現のグループに名前を付けて、マッチ結果を $matches['名前'] のように意味のあるキーで参照できるようにする機能です。

番号で参照する限界

正規表現のキャプチャを $matches[1]$matches[2] と番号で参照するコード、動きはしますが後から読むとつらいですよね。グループの順番を入れ替えると番号がずれてバグる、というのもよくある事故です。名前付きキャプチャを使うと、この番号地獄から抜け出せます。

// 番号参照だと、どれが何か分かりにくい
preg_match('/(\d{4})-(\d{2})-(\d{2})/', '2026-07-22', $m);
echo $m[1]; // これは年…だっけ?

(?<name>…)で名前を付ける

グループの先頭に ?<name> を書くと、そのグループに名前が付きます。?'name'?P<name> でも同じ意味ですが、私は ?<name> を使うことが多いです。マッチ結果は $matches['name'] で引けるようになり、意図が一目で分かります。

$pattern = '/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/';

preg_match($pattern, '2026-07-22', $m);

echo $m['year'];  // 2026
echo $m['month']; // 07
echo $m['day'];   // 22

ちなみに名前付きにしても番号での参照は生きているので、$m[1] でも取れます。移行の途中で両方混ぜても動くのは地味に助かるところですね。

置換とループでの活用

置換のバックリファレンスでも名前が使えます。preg_replace なら ${name} の形で参照できて、フォーマット変換のパターンが読みやすくなります。複数行を回して連想配列に詰めるときも、名前付きだとそのまま意味のあるキーになるのが便利です。

// 日付フォーマットを入れ替える
$out = preg_replace(
    '/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/',
    '${d}/${m}/${y}',
    '2026-07-22'
);
// "22/07/2026"

// ログ行のパースをそのまま連想配列に
$log = '192.168.0.1 GET /index';
preg_match('/(?<ip>\S+) (?<method>\S+) (?<path>\S+)/', $log, $m);
$record = [
    'ip'     => $m['ip'],
    'method' => $m['method'],
    'path'   => $m['path'],
];

注意点として、同じ名前を複数のグループに付けるとエラーになります。また $matches には名前付きキーと番号キーの両方が入るので、そのまま JSON にすると重複した情報が出ます。必要なキーだけ拾い直すのが無難だと思います。

まとめ

名前付きキャプチャは、正規表現の結果に意味のあるラベルを付けて読みやすくするための機能です。グループ順の変更に強くなること、置換のバックリファレンスにも名前が使えることが実務での利点ですね。番号キーも同時に残る点だけ意識しておけば、複雑なパターンのメンテがずいぶん楽になると思います。

よくある質問

Q. どう書けば名前が付きますか?
A. グループの先頭に (?<name>...) と書きます。(?'name'...)(?P<name>...) でも同じ意味です。

Q. 名前を付けると番号では引けなくなりますか?
A. 引けます。名前付きにしても番号キーは残るので、$m[1] でも $m['name'] でも取れます。移行の途中で混ぜても動きます。

Q. 置換でも名前を使えますか?
A. 使えます。preg_replace のバックリファレンスで ${name} の形で参照できます。

類似投稿

コメントを残す

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