[PHP]preg_replace_callback_array関数の使い方を完全解説!複数パターンを一度に処理する方法

PHP

はじめに

PHPで正規表現による文字列置換を行う際、複数のパターンを処理したい場面はよくありますよね。従来はpreg_replace_callbackを何度も呼び出す必要がありましたが、PHP 7.0以降ではpreg_replace_callback_array関数を使うことで、複数のパターンとコールバック関数をまとめて処理できるようになりました。

この記事では、preg_replace_callback_arrayの基本から実践的な使い方まで、サンプルコードを交えながら詳しく解説します。

preg_replace_callback_arrayとは?

preg_replace_callback_arrayは、複数の正規表現パターンとそれぞれに対応するコールバック関数を配列で指定し、文字列置換を一度に実行できる関数です。

基本構文

preg_replace_callback_array(
    array $pattern_callback_array,
    string|array $subject,
    int $limit = -1,
    int &$count = null,
    int $flags = 0
): string|array|null

パラメータ

  • $pattern_callback_array: パターンとコールバック関数の連想配列
  • $subject: 検索・置換対象の文字列(または配列)
  • $limit: 各パターンの最大置換回数(デフォルト: -1=無制限)
  • $count: 実行された置換の総数を格納する変数(参照渡し)
  • $flags: オプションフラグ

基本的な使い方

シンプルな例

HTMLタグを一度に処理する例を見てみましょう。

<?php
$text = "こんにちは、<b>太字</b>と<i>斜体</i>のテキストです。";

$result = preg_replace_callback_array(
    [
        // <b>タグを**で囲む
        '/<b>(.*?)<\/b>/' => function($matches) {
            return '**' . $matches[1] . '**';
        },
        // <i>タグを__で囲む
        '/<i>(.*?)<\/i>/' => function($matches) {
            return '__' . $matches[1] . '__';
        }
    ],
    $text
);

echo $result;
// 出力: こんにちは、**太字**と__斜体__のテキストです。
?>

実践的な使用例

例1: マークダウン風のテキスト変換

<?php
$markdown = "見出しは #タイトル# で、リンクは [リンク文字](URL) で表現します。";

$html = preg_replace_callback_array(
    [
        // #見出し# → <h2>見出し</h2>
        '/#(.*?)#/' => function($m) {
            return '<h2>' . htmlspecialchars($m[1]) . '</h2>';
        },
        // [テキスト](URL) → <a href="URL">テキスト</a>
        '/\[(.*?)\]\((.*?)\)/' => function($m) {
            return '<a href="' . htmlspecialchars($m[2]) . '">' 
                   . htmlspecialchars($m[1]) . '</a>';
        }
    ],
    $markdown
);

echo $html;
?>

例2: 個人情報のマスキング

<?php
$text = "電話: 090-1234-5678、メール: example@test.com";

$masked = preg_replace_callback_array(
    [
        // 電話番号をマスク
        '/(\d{3})-(\d{4})-(\d{4})/' => function($m) {
            return $m[1] . '-****-' . $m[3];
        },
        // メールアドレスをマスク
        '/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/' => function($m) {
            return substr($m[1], 0, 2) . '***@' . $m[2];
        }
    ],
    $text
);

echo $masked;
// 出力: 電話: 090-****-5678、メール: ex***@test.com
?>

例3: 価格表示の整形

<?php
$text = "商品Aは1000円、商品Bは2500円、商品Cは10000円です。";

$formatted = preg_replace_callback_array(
    [
        // 4桁以上の数字をカンマ区切りに
        '/(\d)(?=(\d{3})+(?!\d))/' => function($m) {
            return $m[1] . ',';
        },
        // 数字+円を装飾
        '/(\d[\d,]*)円/' => function($m) {
            return '<span class="price">¥' . $m[1] . '</span>';
        }
    ],
    $text
);

echo $formatted;
// 出力: 商品Aは<span class="price">¥1,000</span>、...
?>

preg_replace_callbackとの違い

従来の方法(preg_replace_callback)

<?php
$text = "Hello World";
$text = preg_replace_callback('/Hello/', function($m) {
    return 'Hi';
}, $text);
$text = preg_replace_callback('/World/', function($m) {
    return 'PHP';
}, $text);
?>

preg_replace_callback_arrayを使った方法

<?php
$text = "Hello World";
$text = preg_replace_callback_array([
    '/Hello/' => fn($m) => 'Hi',
    '/World/' => fn($m) => 'PHP'
], $text);
?>

メリット:

  • コードがスッキリして読みやすい
  • パターンとコールバックの対応が明確
  • パフォーマンスが若干向上(内部で最適化される)

置換回数の制限と確認

<?php
$text = "cat cat dog dog bird bird";

$result = preg_replace_callback_array(
    [
        '/cat/' => fn($m) => '猫',
        '/dog/' => fn($m) => '犬',
        '/bird/' => fn($m) => '鳥'
    ],
    $text,
    1,  // 各パターンで最大1回まで置換
    $count  // 置換回数を取得
);

echo $result . "\n";
// 出力: 猫 cat 犬 dog 鳥 bird

echo "置換回数: {$count}回\n";
// 出力: 置換回数: 3回
?>

よくある使用例とパターン

URLの自動リンク化

<?php
function autoLink($text) {
    return preg_replace_callback_array([
        // HTTPSリンク
        '/(https?:\/\/[^\s]+)/' => function($m) {
            return '<a href="' . $m[1] . '" target="_blank">' 
                   . $m[1] . '</a>';
        },
        // メールアドレス
        '/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/' => function($m) {
            return '<a href="mailto:' . $m[1] . '">' . $m[1] . '</a>';
        }
    ], $text);
}

$text = "お問い合わせはinfo@example.comまで。詳細はhttps://example.comをご覧ください。";
echo autoLink($text);
?>

注意点とベストプラクティス

1. パターンの実行順序

配列の順序でパターンが適用されるため、順序が重要な場合は注意が必要です。

<?php
// 悪い例:先に広範なパターンを適用
$bad = preg_replace_callback_array([
    '/\d+/' => fn($m) => '[数字]',  // すべての数字
    '/\d{3}-\d{4}/' => fn($m) => '[郵便番号]'  // 届かない!
], '郵便番号は123-4567です');

// 良い例:具体的なパターンを先に
$good = preg_replace_callback_array([
    '/\d{3}-\d{4}/' => fn($m) => '[郵便番号]',  // 先に
    '/\d+/' => fn($m) => '[数字]'
], '郵便番号は123-4567です');
?>

2. エスケープ処理

ユーザー入力を扱う場合は必ずエスケープを行いましょう。

<?php
$result = preg_replace_callback_array([
    '/{{(.*?)}}/' => function($m) {
        // XSS対策
        return htmlspecialchars($m[1], ENT_QUOTES, 'UTF-8');
    }
], $text);
?>

3. パフォーマンスの考慮

大量のテキスト処理では、不要な処理を避けましょう。

<?php
// 置換が必要かチェックしてから実行
if (preg_match('/<[^>]+>/', $text)) {
    $text = preg_replace_callback_array([...], $text);
}
?>

まとめ

preg_replace_callback_arrayは、複数の正規表現パターンを効率的に処理できる強力な関数です。

主な特徴:

  • ✅ 複数パターンを一度に処理できる
  • ✅ コードの可読性が向上する
  • ✅ PHP 7.0以降で使用可能
  • ✅ 柔軟なコールバック処理が可能

複雑なテキスト処理を行う際は、ぜひこの関数を活用してみてください!

参考リンク


この記事が役に立ったら、ぜひシェアしてください!

タイトルとURLをコピーしました