【PHP8.x】preg_match_all()関数の使い方
preg_match_all関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
preg_match_all関数は、指定された文字列の中から正規表現に一致するすべてのパターンを検索し、その結果を配列として取得する関数です。この関数は、単一のパターンに一致する箇所だけでなく、対象の文字列内に存在する複数のパターン一致を一度に収集したい場合に非常に有用です。
この関数は主に三つの引数を使用します。一つ目は、検索したいパターンを定義する「正規表現パターン」です。正規表現は、特定の文字の並びや形式を記述するための強力な記法です。二つ目は、検索の対象となる「文字列」です。そして三つ目は、検索結果を格納するための「配列」で、この配列に一致したすべての情報が整理されて格納されます。
結果の格納方法については、flags引数を用いて制御できます。例えば、PREG_PATTERN_ORDERやPREG_SET_ORDERといった定数を指定することで、結果配列の構造を調整することが可能です。さらに、検索を開始する文字位置をoffset引数で指定することもできます。
preg_match_all関数は、マッチしたパターンの総数を整数で返します。一致するパターンが一つも見つからなかった場合は0を返します。また、何らかの内部エラーが発生した際にはfalseを返しますので、戻り値の確認は重要です。この関数は、ログ解析、データ抽出、入力値の複雑な検証など、システム開発における多様な文字列処理の場面で広く活用されます。
構文(syntax)
1<?php 2$pattern = '/search_pattern/i'; 3$subject = 'This is a string with search_pattern and another search_pattern.'; 4$matches = []; 5preg_match_all($pattern, $subject, $matches); 6?>
引数(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抽出
1<?php 2 3/** 4 * 複数行の文字列から、指定された正規表現パターンにマッチする全てのログIDを抽出します。 5 * 6 * この関数は、複数行モード(`m`修飾子)を使用して、各行の先頭からパターンを検索します。 7 * 具体的には「Log ID: [XXXX-YYY]」のような形式のログIDを抽出することを目的としています。 8 * 9 * @param string $subject 検索対象となる複数行の文字列。 10 * @return array 抽出されたログIDの配列。マッチが見つからない場合は空の配列を返します。 11 */ 12function extractMultilineLogIds(string $subject): array 13{ 14 // 正規表現パターンを定義します。 15 // /^Log ID: \[(?<logId>[A-Z]{3,}-[0-9]{3,})\]/m 16 // - ^ : 各行の先頭にマッチします(末尾の /m 修飾子により)。 17 // - Log ID: \ : リテラルの文字列 "Log ID: " にマッチします。スペースとコロンを含みます。 18 // - \[ : リテラルの "[" 文字にマッチします(特殊文字なのでエスケープが必要です)。 19 // - (?<logId>...) : 'logId' という名前付きキャプチャグループを定義します。 20 // - [A-Z]{3,}-[0-9]{3,}: ログIDの具体的なパターンです。 21 // 大文字アルファベット3文字以上(例: "ALPHA") 22 // ハイフン(例: "-") 23 // 数字3桁以上(例: "101") 24 // - \] : リテラルの "]" 文字にマッチします(特殊文字なのでエスケープが必要です)。 25 // - /m : マルチラインモード修飾子です。 26 // これにより、^と$が文字列全体の先頭/末尾だけでなく、各行の先頭/末尾にもマッチするようになります。 27 $pattern = '/^Log ID: \[(?<logId>[A-Z]{3,}-[0-9]{3,})\]/m'; 28 29 $matches = []; // マッチした結果を格納するための配列を初期化します。 30 31 // preg_match_all 関数を使用して、検索対象文字列からパターンに一致する全ての箇所を検索します。 32 // - $pattern: 使用する正規表現パターン。 33 // - $subject: 検索対象の文字列。 34 // - $matches: マッチした結果が格納される配列(参照渡し)。 35 // - PREG_SET_ORDER: このフラグは、$matches配列の構造を決定します。 36 // 各マッチごとに要素の配列として結果を格納します。 37 // 例: [ ['全体マッチ1', 'logId' => '値1'], ['全体マッチ2', 'logId' => '値2'] ] 38 // preg_match_all は、マッチした回数を返します。マッチしなかった場合は 0、エラーの場合は false を返します。 39 $matchCount = preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER); 40 41 $extractedLogIds = []; // 抽出されたログIDを格納する配列を初期化します。 42 43 // マッチが成功し、かつ1つ以上のマッチが見つかった場合 44 if ($matchCount !== false && $matchCount > 0) { 45 foreach ($matches as $match) { 46 // 名前付きキャプチャグループ 'logId' の値が存在すれば、それを結果配列に追加します。 47 if (isset($match['logId'])) { 48 $extractedLogIds[] = $match['logId']; 49 } 50 } 51 } 52 53 return $extractedLogIds; 54} 55 56// テスト用の複数行文字列を定義します。 57$multiLineText = <<<EOT 58This is the first line of the document. 59Log ID: [ALPHA-101] - Critical system event. 60Another line with some general information. 61Log ID: [BETA-202] - User login successful. 62A line with an invalid ID format: [XYZ-abc]. 63Log ID: [GAMMA-303] - Data processing complete. 64This line does not contain a log ID. 65Log ID: [DELTA-404] - Backup initiated. 66End of the document. 67EOT; 68 69// 定義した関数を呼び出し、結果を取得します。 70$foundLogIds = extractMultilineLogIds($multiLineText); 71 72// 抽出されたログIDを出力します。 73if (!empty($foundLogIds)) { 74 echo "Found Log IDs:\n"; 75 foreach ($foundLogIds as $id) { 76 echo "- " . $id . "\n"; 77 } 78} else { 79 echo "No Log IDs found in the text.\n"; 80} 81 82?>
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でないことを確認し、エラー時の挙動を考慮してください。引数$flagsにPREG_SET_ORDERを指定すると、$matches配列は各マッチごとに要素の配列として格納されます。名前付きキャプチャグループ(?<logId>...)を使用すると、$match['logId']のようにマッチ結果にアクセスしやすくなります。正規表現内で[や]のような特殊文字をリテラルとして扱いたい場合は、必ずバックスラッシュ\でエスケープしてください。
PHP preg_match_allでスペースを含む単語ペアを検索する
1<?php 2 3/** 4 * preg_match_all_example_allow_space 5 * 6 * この関数は、指定された文字列の中から、間にスペースを含む単語のペアをすべて検索し、 7 * その結果を表示します。 8 * `preg_match_all` 関数を使用して、正規表現でスペースを許容するパターンを扱います。 9 */ 10function preg_match_all_example_allow_space(): void 11{ 12 // 検索対象の文字列 13 $subject = "Hello World, PHP 8 is awesome. This is a good example. NoSpaceHere."; 14 15 // 正規表現パターンを定義 16 // \b は単語の境界(Word Boundary)を表します。 17 // \w+ は1つ以上の単語文字(アルファベット、数字、アンダースコア)にマッチします。 18 // \s+ は1つ以上のホワイトスペース文字(スペース、タブ、改行など)にマッチします。 19 // このパターンは「単語 スペース 単語」の形式を探します。 20 $pattern = '/\b\w+\s+\w+\b/'; 21 22 // マッチした結果を格納する配列(参照渡し) 23 $matches = []; 24 25 // preg_match_all を呼び出し、パターンにマッチする全ての出現を検索 26 // 返り値はマッチした回数、失敗した場合は false 27 $numMatches = preg_match_all($pattern, $subject, $matches); 28 29 echo "検索対象文字列: \"{$subject}\"\n"; 30 echo "正規表現パターン: \"{$pattern}\"\n\n"; 31 32 if ($numMatches === false) { 33 echo "エラー: preg_match_all の実行に失敗しました。\n"; 34 } elseif ($numMatches === 0) { 35 echo "マッチする結果は見つかりませんでした。\n"; 36 } else { 37 echo "マッチした回数: {$numMatches}回\n"; 38 echo "マッチした結果:\n"; 39 40 // $matches 配列の構造について: 41 // $matches[0] には、パターン全体にマッチした文字列の配列が格納されます。 42 // $matches[1] 以降には、正規表現内のキャプチャグループ(例: (...))に 43 // マッチした文字列の配列が格納されます。 44 // 今回のパターンにはキャプチャグループがないため、$matches[0] のみが意味を持ちます。 45 foreach ($matches[0] as $match) { 46 echo " - {$match}\n"; 47 } 48 } 49} 50 51// 関数を実行 52preg_match_all_example_allow_space();
PHP 8のpreg_match_all関数は、指定された文字列の中から正規表現パターンに合致する全ての部分を検索し、その結果をまとめて取得します。このサンプルコードは、preg_match_allを使用して、間にスペースを含む単語のペアをすべて見つける具体的な方法を示しています。
この関数は、検索対象の正規表現パターン、検索対象文字列、そしてマッチした結果を格納する配列の三つの主要な引数を受け取ります。$pattern引数には、今回の例では/\b\w+\s+\w+\b/という正規表現が指定されています。これは「単語の境界で区切られた単語」、その後に「1つ以上のスペース」、そして再び「単語の境界で区切られた単語」という組み合わせを探すことを意味します。$subject引数に検索対象の文字列が渡され、$matches引数にはマッチした結果が配列として格納されます。$matchesは参照渡しであり、関数実行後には$matches[0]にパターン全体にマッチした全ての文字列が配列として格納されます。
preg_match_allは、マッチした回数を整数で返します。マッチする部分が見つからなければ0を、実行に失敗した場合はfalseを返します。サンプルコードでは、この戻り値に基づいて処理を分岐し、マッチが見つかった場合には$matches[0]の内容を一つずつ表示しています。例えば、「Hello World」や「PHP 8」のようにスペースで区切られた単語のペアが結果として出力されます。この関数を習得することで、文字列から特定の形式の情報を効率的に抽出できるようになります。
正規表現の記述は厳密さが求められます。特に\s+はスペースだけでなく、タブや改行も含むため、意図しないマッチがないかパターンをよく確認してください。$matches引数にはマッチした結果が格納され、参照渡しであるため、呼び出し前に空の配列で初期化しておくのが一般的です。また、$matches[0]にはパターン全体にマッチした結果が、キャプチャグループがあれば$matches[1]以降にそれぞれの結果が入る配列構造を理解することが重要です。関数の戻り値はマッチした回数か、処理失敗時のfalseです。必ず厳密な比較演算子===でfalseでないか確認し、エラー処理を行うことで、予期せぬ挙動を防ぎ、安全なコードになります。
PHP preg_match_all vs preg_match 使い方
1<?php 2 3/** 4 * preg_match と preg_match_all の違いを示すサンプルコード 5 * 6 * このコードは、システムエンジニアを目指す初心者が、PHPの正規表現関数である 7 * preg_match と preg_match_all の基本的な動作と、その結果の違いを理解できるように作成されています。 8 * 9 * preg_match: 10 * 文字列内でパターンに最初にマッチした部分のみを検索します。 11 * マッチが見つかると 1 を返し、見つからない場合は 0 を返します。 12 * $matches 配列には、最初のマッチとそのキャプチャグループが格納されます。 13 * 14 * preg_match_all: 15 * 文字列内でパターンにマッチする全ての部分を検索します。 16 * 見つかったマッチの総数を返します。 17 * $matches 配列には、パターン全体のマッチが配列として格納されます(デフォルトの PREG_PATTERN_ORDER)。 18 */ 19 20// 対象となる文字列を定義します。この文字列には複数の数字が含まれています。 21$subject = "商品Aの価格は120円、商品Bは80円、商品Cは250円です。割引後、合計は350円になります。"; 22 23// 1つ以上の数字(数値)にマッチする正規表現パターンを定義します。 24// \d+ は「1桁以上の数字」を意味します。 25$pattern = '/\d+/'; 26 27echo "--- preg_match の実行結果 ---" . PHP_EOL; 28$matches_preg_match = []; // preg_match の結果を格納する配列を初期化 29 30// preg_match を実行します。 31// $result_preg_match は 1 (マッチあり) または 0 (マッチなし) を返します。 32$result_preg_match = preg_match($pattern, $subject, $matches_preg_match); 33 34if ($result_preg_match === 1) { 35 echo "preg_match が見つけたマッチ数: " . $result_preg_match . " (最初のマッチのみ)" . PHP_EOL; 36 echo "見つかった最初のマッチ: " . $matches_preg_match[0] . PHP_EOL; 37 echo "matches配列の内容:" . PHP_EOL; 38 print_r($matches_preg_match); 39} elseif ($result_preg_match === 0) { 40 echo "preg_match はマッチを見つけませんでした。" . PHP_EOL; 41} else { 42 echo "preg_match の実行中にエラーが発生しました。" . PHP_EOL; 43} 44echo PHP_EOL; // 結果を見やすくするために改行 45 46echo "--- preg_match_all の実行結果 ---" . PHP_EOL; 47$matches_preg_match_all = []; // preg_match_all の結果を格納する配列を初期化 48 49// preg_match_all を実行します。 50// $result_preg_match_all は見つかったマッチの総数を返します。 51$result_preg_match_all = preg_match_all($pattern, $subject, $matches_preg_match_all); 52 53if ($result_preg_match_all > 0) { 54 echo "preg_match_all が見つけたマッチ数: " . $result_preg_match_all . " (全てのマッチ)" . PHP_EOL; 55 // $matches_preg_match_all[0] には、見つかった全ての完全なマッチが配列として格納されます。 56 echo "見つかった全てのマッチ: " . implode(', ', $matches_preg_match_all[0]) . PHP_EOL; 57 echo "matches配列の内容 (全てのマッチ):" . PHP_EOL; 58 print_r($matches_preg_match_all); 59} elseif ($result_preg_match_all === 0) { 60 echo "preg_match_all はマッチを見つけませんでした。" . PHP_EOL; 61} else { 62 echo "preg_match_all の実行中にエラーが発生しました。" . PHP_EOL; 63} 64 65?>
PHPのpreg_match_all関数は、文字列の中から正規表現パターンに合致する「全て」の部分を効率的に検索し、その結果を取得する際に利用されます。この関数は、第一引数$patternで指定した正規表現を、第二引数$subjectの対象文字列に適用します。マッチした全ての部分は、第三引数$matchesに渡された配列変数に格納されます。この$matches配列には、デフォルトでは全てのマッチが一次元配列として$matches[0]に、キャプチャグループごとのマッチがそれ以降のキーに格納される特徴があります。
preg_match_allと似た機能を持つpreg_match関数との主な違いは、検索範囲にあります。preg_matchがパターンに「最初」にマッチした部分のみを検索して結果を返すのに対し、preg_match_allは文字列全体からパターンにマッチする「全て」の部分を見つけ出します。
関数は、見つかったマッチの総数を整数で返します。マッチが一つも見つからなかった場合は0を、正規表現に問題があるなどのエラーが発生した場合はfalseを返します。
提示されたサンプルコードでは、preg_matchが対象文字列から最初の数字「120」だけを見つける一方、preg_match_allが「120, 80, 250, 350」という全ての数字を抽出する様子を通じて、両関数の検索挙動と結果の違いが明確に示されています。これにより、大量のデータから特定のパターンを網羅的に抽出する際にpreg_match_allが非常に強力なツールであることが理解できます。
preg_match_all関数は、対象文字列内でパターンにマッチする全ての箇所を検索してその総数を返します。これに対し、preg_matchは最初にマッチした箇所のみを検索し、マッチの有無を1か0で返します。どちらの関数も、正規表現の書式エラーなどで失敗した場合はfalseを返しますので、戻り値によるエラー処理を必ず行ってください。
また、マッチ結果が格納される$matches配列の構造が両者で異なる点に注意が必要です。preg_match_allでは、デフォルト設定の場合、$matches[0]に全ての完全なマッチが配列として格納されます。一方、preg_matchでは$matches[0]に最初の完全なマッチが単一の文字列として格納されます。$matches引数は参照渡しですので、関数呼び出し前に空の配列で初期化しておくことをお勧めします。
PHP preg_match_allで複数マッチを取得する
1<?php 2 3/** 4 * preg_match_all関数の基本的な使い方を示すサンプルコードです。 5 * 文字列内から、指定された正規表現パターンに合致するすべての出現を検索し、その結果を表示します。 6 */ 7 8// 検索対象となる文字列を定義します。 9$subject = "商品Aは150円、商品Bは280.50円、商品Cは300円です。合計5個。"; 10 11// 検索する正規表現パターンを定義します。 12// このパターンは、整数または小数点を含む数値を検索します。 13// \d+ : 1回以上の数字にマッチします。 14// (\.\d+)? : ピリオドとそれに続く1回以上の数字にマッチします。 15// 全体が ? (オプション) なので、整数のみの場合にもマッチします。 16// この括弧 `()` は「キャプチャグループ」と呼ばれ、マッチした部分を別途取得できます。 17$pattern = '/\d+(\.\d+)?/'; 18 19// preg_match_all の結果を格納する配列を初期化します。 20// この配列には、見つかったすべてのマッチが構造化された形式で格納されます。 21$matches = []; 22 23// preg_match_all 関数を実行します。 24// 引数: 25// $pattern: 検索パターン (正規表現) 26// $subject: 検索対象の文字列 27// $matches: 結果を格納するための配列 (参照渡し)。関数によって内容が更新されます。 28// 戻り値: 29// 見つかった完全なマッチの数、またはエラーの場合は false。 30$numMatches = preg_match_all($pattern, $subject, $matches); 31 32// 実行結果を評価し、コンソールに出力します。 33if ($numMatches === false) { 34 echo "エラーが発生しました。正規表現のパターンを確認してください。\n"; 35} elseif ($numMatches > 0) { 36 echo "文字列内から " . $numMatches . " 個の数値が見つかりました。\n\n"; 37 echo "元の文字列: \"" . $subject . "\"\n"; 38 echo "使用した正規表現パターン: \"" . $pattern . "\"\n\n"; 39 40 // $matches 配列の構造について (デフォルトのPREG_PATTERN_ORDERの場合): 41 // $matches[0] には、正規表現パターン全体に合致したすべての文字列が、見つかった順に格納されます。 42 echo "--- パターン全体にマッチした結果 ---\n"; 43 foreach ($matches[0] as $index => $fullMatch) { 44 echo "マッチ " . ($index + 1) . ": " . $fullMatch . "\n"; 45 } 46 47 // $matches[1] (もし存在すれば) には、最初のキャプチャグループ `()` にマッチしたすべての文字列が格納されます。 48 // マッチしなかった場合、その要素は空文字列になります。 49 if (isset($matches[1]) && !empty(array_filter($matches[1]))) { 50 echo "\n--- キャプチャグループ1 (小数部) にマッチした結果 ---\n"; 51 foreach ($matches[1] as $index => $capturedGroup) { 52 // キャプチャグループがマッチしなかった場合は空文字列なので、その場合は表示をスキップします。 53 if ($capturedGroup !== '') { 54 echo "マッチ " . ($index + 1) . " の小数部: " . $capturedGroup . "\n"; 55 } 56 } 57 } 58 59} else { 60 echo "文字列内にパターンに合致する数値は見つかりませんでした。\n"; 61} 62 63?>
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)のように、厳密な型比較で行うことが重要です。また、正規表現パターンは/(スラッシュ)のようなデリミタで囲む必要があります。