【PHP8.x】preg_match_all関数の使い方

作成日: 更新日:

preg_match_all関数は、指定された文字列の中から正規表現に一致するすべてのパターンを検索し、その結果を配列として取得する関数です。この関数は、単一のパターンに一致する箇所だけでなく、対象の文字列内に存在する複数のパターン一致を一度に収集したい場合に非常に有用です。

この関数は主に三つの引数を使用します。一つ目は、検索したいパターンを定義する「正規表現パターン」です。正規表現は、特定の文字の並びや形式を記述するための強力な記法です。二つ目は、検索の対象となる「文字列」です。そして三つ目は、検索結果を格納するための「配列」で、この配列に一致したすべての情報が整理されて格納されます。

結果の格納方法については、flags引数を用いて制御できます。例えば、PREG_PATTERN_ORDERPREG_SET_ORDERといった定数を指定することで、結果配列の構造を調整することが可能です。さらに、検索を開始する文字位置をoffset引数で指定することもできます。

preg_match_all関数は、マッチしたパターンの総数を整数で返します。一致するパターンが一つも見つからなかった場合は0を返します。また、何らかの内部エラーが発生した際にはfalseを返しますので、戻り値の確認は重要です。この関数は、ログ解析、データ抽出、入力値の複雑な検証など、システム開発における多様な文字列処理の場面で広く活用されます。

基本的な使い方

構文(syntax)

<?php
$pattern = '/search_pattern/i';
$subject = 'This is a string with search_pattern and another search_pattern.';
$matches = [];
preg_match_all($pattern, $subject, $matches);
?>

引数(parameters)

string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0

  • string $pattern: 検索する正規表現パターンを指定する文字列
  • string $subject: 検索対象となる文字列
  • array &$matches = null: マッチした部分文字列を格納する配列。参照渡しで渡され、関数実行後に結果が格納されます。
  • int $flags = 0: 検索の挙動を制御するフラグを指定する整数
  • int $offset = 0: $subject の検索を開始するオフセット位置を指定する整数

戻り値(return)

int|false

preg_match_all 関数は、正規表現にマッチした全ての出現箇所を $matches 配列に格納し、マッチした総数を整数で返します。エラーが発生した場合は false を返します。

サンプルコード

PHP preg_match_all による複数行ログID抽出

<?php

/**
 * 複数行の文字列から、指定された正規表現パターンにマッチする全てのログIDを抽出します。
 *
 * この関数は、複数行モード(`m`修飾子)を使用して、各行の先頭からパターンを検索します。
 * 具体的には「Log ID: [XXXX-YYY]」のような形式のログIDを抽出することを目的としています。
 *
 * @param string $subject 検索対象となる複数行の文字列。
 * @return array 抽出されたログIDの配列。マッチが見つからない場合は空の配列を返します。
 */
function extractMultilineLogIds(string $subject): array
{
    // 正規表現パターンを定義します。
    // /^Log ID: \[(?<logId>[A-Z]{3,}-[0-9]{3,})\]/m
    // - ^                 : 各行の先頭にマッチします(末尾の /m 修飾子により)。
    // - Log ID: \         : リテラルの文字列 "Log ID: " にマッチします。スペースとコロンを含みます。
    // - \[                : リテラルの "[" 文字にマッチします(特殊文字なのでエスケープが必要です)。
    // - (?<logId>...)     : 'logId' という名前付きキャプチャグループを定義します。
    // - [A-Z]{3,}-[0-9]{3,}: ログIDの具体的なパターンです。
    //                       大文字アルファベット3文字以上(例: "ALPHA")
    //                       ハイフン(例: "-")
    //                       数字3桁以上(例: "101")
    // - \]                : リテラルの "]" 文字にマッチします(特殊文字なのでエスケープが必要です)。
    // - /m                : マルチラインモード修飾子です。
    //                       これにより、^と$が文字列全体の先頭/末尾だけでなく、各行の先頭/末尾にもマッチするようになります。
    $pattern = '/^Log ID: \[(?<logId>[A-Z]{3,}-[0-9]{3,})\]/m';

    $matches = []; // マッチした結果を格納するための配列を初期化します。

    // preg_match_all 関数を使用して、検索対象文字列からパターンに一致する全ての箇所を検索します。
    // - $pattern: 使用する正規表現パターン。
    // - $subject: 検索対象の文字列。
    // - $matches: マッチした結果が格納される配列(参照渡し)。
    // - PREG_SET_ORDER: このフラグは、$matches配列の構造を決定します。
    //                   各マッチごとに要素の配列として結果を格納します。
    //                   例: [ ['全体マッチ1', 'logId' => '値1'], ['全体マッチ2', 'logId' => '値2'] ]
    // preg_match_all は、マッチした回数を返します。マッチしなかった場合は 0、エラーの場合は false を返します。
    $matchCount = preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);

    $extractedLogIds = []; // 抽出されたログIDを格納する配列を初期化します。

    // マッチが成功し、かつ1つ以上のマッチが見つかった場合
    if ($matchCount !== false && $matchCount > 0) {
        foreach ($matches as $match) {
            // 名前付きキャプチャグループ 'logId' の値が存在すれば、それを結果配列に追加します。
            if (isset($match['logId'])) {
                $extractedLogIds[] = $match['logId'];
            }
        }
    }

    return $extractedLogIds;
}

// テスト用の複数行文字列を定義します。
$multiLineText = <<<EOT
This is the first line of the document.
Log ID: [ALPHA-101] - Critical system event.
Another line with some general information.
Log ID: [BETA-202] - User login successful.
A line with an invalid ID format: [XYZ-abc].
Log ID: [GAMMA-303] - Data processing complete.
This line does not contain a log ID.
Log ID: [DELTA-404] - Backup initiated.
End of the document.
EOT;

// 定義した関数を呼び出し、結果を取得します。
$foundLogIds = extractMultilineLogIds($multiLineText);

// 抽出されたログIDを出力します。
if (!empty($foundLogIds)) {
    echo "Found Log IDs:\n";
    foreach ($foundLogIds as $id) {
        echo "- " . $id . "\n";
    }
} else {
    echo "No Log IDs found in the text.\n";
}

?>

PHPのpreg_match_all関数は、指定された正規表現パターンに一致する文字列中の全ての箇所を検索し、その結果を取得するために使用されます。このサンプルコードでは、複数行の文字列から「Log ID: [XXXX-YYY]」のような特定の形式のログIDを全て抽出する方法を示しています。

preg_match_all関数は、最初の引数に検索に使用する正規表現パターン$pattern、二番目の引数に検索対象の文字列$subject、三番目の引数にマッチ結果を格納する配列&$matchesを受け取ります。正規表現パターンの末尾にある/m修飾子により、^が文字列全体の先頭だけでなく各行の先頭にもマッチする「マルチラインモード」で検索が行われます。これにより、複数行の中から各行のログIDを効率的に見つけることが可能です。また、PREG_SET_ORDERフラグは、$matches配列を各マッチごとに要素の配列として構成し、名前付きキャプチャグループ?<logId>を使って抽出されたIDにアクセスしやすくします。

関数の戻り値は、マッチした回数を示すint型、またはエラーが発生した場合はfalseです。サンプルコードでは、戻り値を確認してマッチが成功したか判断し、$matches配列からlogIdとしてキャプチャされた値を抽出し、結果として配列で返しています。このようにpreg_match_allを使用することで、複雑なテキストデータから必要な情報を効率的に収集することができます。

複数行の文字列からパターンを抽出する際、正規表現に/m修飾子を含めることは非常に重要です。これにより^が各行の先頭にマッチし、期待通りの検索が可能になります。preg_match_all関数の戻り値は、マッチ件数かエラー時にfalseです。処理を進める前に必ずfalseでないことを確認し、エラー時の挙動を考慮してください。引数$flagsPREG_SET_ORDERを指定すると、$matches配列は各マッチごとに要素の配列として格納されます。名前付きキャプチャグループ(?<logId>...)を使用すると、$match['logId']のようにマッチ結果にアクセスしやすくなります。正規表現内で[]のような特殊文字をリテラルとして扱いたい場合は、必ずバックスラッシュ\でエスケープしてください。

PHP preg_match_allで複数マッチを取得する

<?php

/**
 * preg_match_all関数の基本的な使い方を示すサンプルコードです。
 * 文字列内から、指定された正規表現パターンに合致するすべての出現を検索し、その結果を表示します。
 */

// 検索対象となる文字列を定義します。
$subject = "商品Aは150円、商品Bは280.50円、商品Cは300円です。合計5個。";

// 検索する正規表現パターンを定義します。
// このパターンは、整数または小数点を含む数値を検索します。
// \d+        : 1回以上の数字にマッチします。
// (\.\d+)?   : ピリオドとそれに続く1回以上の数字にマッチします。
//              全体が ? (オプション) なので、整数のみの場合にもマッチします。
//              この括弧 `()` は「キャプチャグループ」と呼ばれ、マッチした部分を別途取得できます。
$pattern = '/\d+(\.\d+)?/';

// preg_match_all の結果を格納する配列を初期化します。
// この配列には、見つかったすべてのマッチが構造化された形式で格納されます。
$matches = [];

// preg_match_all 関数を実行します。
// 引数:
//   $pattern:  検索パターン (正規表現)
//   $subject:  検索対象の文字列
//   $matches:  結果を格納するための配列 (参照渡し)。関数によって内容が更新されます。
// 戻り値:
//   見つかった完全なマッチの数、またはエラーの場合は false。
$numMatches = preg_match_all($pattern, $subject, $matches);

// 実行結果を評価し、コンソールに出力します。
if ($numMatches === false) {
    echo "エラーが発生しました。正規表現のパターンを確認してください。\n";
} elseif ($numMatches > 0) {
    echo "文字列内から " . $numMatches . " 個の数値が見つかりました。\n\n";
    echo "元の文字列: \"" . $subject . "\"\n";
    echo "使用した正規表現パターン: \"" . $pattern . "\"\n\n";

    // $matches 配列の構造について (デフォルトのPREG_PATTERN_ORDERの場合):
    // $matches[0] には、正規表現パターン全体に合致したすべての文字列が、見つかった順に格納されます。
    echo "--- パターン全体にマッチした結果 ---\n";
    foreach ($matches[0] as $index => $fullMatch) {
        echo "マッチ " . ($index + 1) . ": " . $fullMatch . "\n";
    }

    // $matches[1] (もし存在すれば) には、最初のキャプチャグループ `()` にマッチしたすべての文字列が格納されます。
    // マッチしなかった場合、その要素は空文字列になります。
    if (isset($matches[1]) && !empty(array_filter($matches[1]))) {
        echo "\n--- キャプチャグループ1 (小数部) にマッチした結果 ---\n";
        foreach ($matches[1] as $index => $capturedGroup) {
            // キャプチャグループがマッチしなかった場合は空文字列なので、その場合は表示をスキップします。
            if ($capturedGroup !== '') {
                echo "マッチ " . ($index + 1) . " の小数部: " . $capturedGroup . "\n";
            }
        }
    }

} else {
    echo "文字列内にパターンに合致する数値は見つかりませんでした。\n";
}

?>

PHPの preg_match_all 関数は、指定した文字列の中から、正規表現パターンに一致する部分をすべて探し出すための関数です。

このサンプルコードでは、まず検索対象となる文字列 $subject と、数値(整数または小数)を探すための正規表現パターン $pattern を定義しています。

preg_match_all 関数を実行すると、第1引数の $pattern を使って第2引数の $subject を検索します。見つかったすべての一致は、第3引数で渡された $matches 配列に格納されます。この引数は参照渡し(&が先頭についている)のため、関数内で $matches の内容が直接更新されます。関数の戻り値は、見つかった一致の総数(この例では4)で、変数 $numMatches に代入されます。

結果が格納される $matches 配列は多次元配列になります。$matches[0] には、パターン全体に一致した文字列('150', '280.50', '300', '5')がすべて格納されます。また、パターン内に括弧 () で囲まれた部分(キャプチャグループ)がある場合、それに一致した部分が $matches[1] 以降に格納されます。この例では、小数部分である '.50' が $matches[1] の対応する要素に格納されています。

preg_match_all関数では、引数$matchesは参照渡しとなるため、事前に初期化された配列を渡す必要があります。関数実行後、この配列に検索結果が格納されます。デフォルトでは、$matches[0]には正規表現全体に合致した文字列が、$matches[1]以降には各キャプチャグループ()に合致した文字列が順番に格納されます。特に、キャプチャグループがマッチしなかった場合、対応する$matchesの要素は空文字列になりますのでご注意ください。関数の戻り値は、マッチした総数を示す整数か、正規表現にエラーがあった場合はfalseを返します。エラーの判定はif ($numMatches === false)のように、厳密な型比較で行うことが重要です。また、正規表現パターンは/(スラッシュ)のようなデリミタで囲む必要があります。

【PHP8.x】preg_match_all関数の使い方 | いっしー@Webエンジニア