はじめに
PHPで文字列から複数のパターンマッチを取得したいとき、preg_match_all関数は非常に強力なツールです。この記事では、初心者の方にも分かりやすく、preg_match_allの基本から実践的な使い方まで詳しく解説します。
preg_match_allとは?
preg_match_allは、PHPの正規表現関数の一つで、文字列内で正規表現パターンにマッチするすべての箇所を検索し、結果を配列に格納します。
似た関数にpreg_matchがありますが、こちらは最初のマッチのみを返すのに対し、preg_match_allはすべてのマッチを取得できる点が大きな違いです。
基本構文
preg_match_all(
string $pattern, // 正規表現パターン
string $subject, // 検索対象の文字列
array &$matches = [], // マッチ結果を格納する配列
int $flags = 0, // フラグ(オプション)
int $offset = 0 // 検索開始位置(オプション)
): int|false
戻り値: マッチした回数を返します。マッチしない場合は0、エラーの場合はfalseを返します。
基本的な使用例
例1: すべての数字を抽出
<?php
$text = "私は2024年10月25日に30個のリンゴを買いました。";
$pattern = '/\d+/'; // 1つ以上の数字にマッチ
preg_match_all($pattern, $text, $matches);
print_r($matches);
/*
出力:
Array
(
[0] => Array
(
[0] => 2024
[1] => 10
[2] => 25
[3] => 30
)
)
*/
echo "数字が" . count($matches[0]) . "個見つかりました。\n";
// 出力: 数字が4個見つかりました。
?>
例2: メールアドレスをすべて抽出
<?php
$text = "連絡先: info@example.com または support@example.jp までご連絡ください。";
$pattern = '/[\w\-\.]+@[\w\-\.]+\.\w+/';
preg_match_all($pattern, $text, $matches);
foreach ($matches[0] as $email) {
echo "メールアドレス: " . $email . "\n";
}
/*
出力:
メールアドレス: info@example.com
メールアドレス: support@example.jp
*/
?>
フラグの使い方
preg_match_allの第4引数には、結果の格納方法を制御するフラグを指定できます。
PREG_PATTERN_ORDER (デフォルト)
パターンごとに結果をグループ化します。
<?php
$text = "山田太郎は35歳、佐藤花子は28歳です。";
$pattern = '/(\w+)は(\d+)歳/u';
preg_match_all($pattern, $text, $matches, PREG_PATTERN_ORDER);
print_r($matches);
/*
Array
(
[0] => Array([0] => 山田太郎は35歳, [1] => 佐藤花子は28歳)
[1] => Array([0] => 山田太郎, [1] => 佐藤花子)
[2] => Array([0] => 35, [1] => 28)
)
*/
?>
PREG_SET_ORDER
マッチごとに結果をグループ化します。データを扱いやすくなります。
<?php
$text = "山田太郎は35歳、佐藤花子は28歳です。";
$pattern = '/(\w+)は(\d+)歳/u';
preg_match_all($pattern, $text, $matches, PREG_SET_ORDER);
print_r($matches);
/*
Array
(
[0] => Array([0] => 山田太郎は35歳, [1] => 山田太郎, [2] => 35)
[1] => Array([0] => 佐藤花子は28歳, [1] => 佐藤花子, [2] => 28)
)
*/
// データの取り出しが簡単
foreach ($matches as $match) {
echo "{$match[1]}さんは{$match[2]}歳です。\n";
}
?>
PREG_OFFSET_CAPTURE
マッチした文字列の位置(オフセット)も取得します。
<?php
$text = "PHP is great. PHP is powerful.";
$pattern = '/PHP/';
preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
/*
Array
(
[0] => Array
(
[0] => Array([0] => PHP, [1] => 0)
[1] => Array([0] => PHP, [1] => 14)
)
)
*/
?>
実践的な使用例
HTMLタグから属性を抽出
<?php
$html = '<img src="photo1.jpg" alt="写真1"><img src="photo2.jpg" alt="写真2">';
$pattern = '/<img\s+src="([^"]+)"\s+alt="([^"]+)">/';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
foreach ($matches as $img) {
echo "画像: {$img[1]}, 説明: {$img[2]}\n";
}
/*
出力:
画像: photo1.jpg, 説明: 写真1
画像: photo2.jpg, 説明: 写真2
*/
?>
URLからパラメータを抽出
<?php
$text = "訪問: https://example.com?id=123&name=test と http://test.com?page=1";
$pattern = '/https?:\/\/[^\s]+/';
preg_match_all($pattern, $text, $matches);
foreach ($matches[0] as $url) {
echo "URL: " . $url . "\n";
}
?>
CSVのようなデータを解析
<?php
$data = "Tokyo,Japan,13000000\nOsaka,Japan,8800000\nKyoto,Japan,1500000";
$pattern = '/^(\w+),(\w+),(\d+)$/m'; // mフラグで複数行対応
preg_match_all($pattern, $data, $matches, PREG_SET_ORDER);
foreach ($matches as $city) {
echo "都市: {$city[1]}, 国: {$city[2]}, 人口: {$city[3]}\n";
}
?>
よくある間違いと注意点
1. デリミタを忘れない
正規表現パターンは必ずデリミタ(通常は/)で囲む必要があります。
// ❌ 間違い
$pattern = '\d+';
// ✅ 正しい
$pattern = '/\d+/';
2. UTF-8文字列を扱う場合はu修飾子を使う
日本語などのマルチバイト文字を正しく扱うには、u修飾子が必要です。
$pattern = '/[あ-ん]+/u'; // uを付ける
3. 特殊文字のエスケープ
正規表現の特殊文字(. * + ? [ ] ( ) { } ^ $ | \)を文字として扱いたい場合は、バックスラッシュでエスケープします。
$pattern = '/\$\d+\.\d+/'; // $10.50 のような金額にマッチ
preg_matchとの使い分け
| 関数 | 用途 |
|---|---|
preg_match | 最初の1つだけマッチすればよい場合 |
preg_match_all | すべてのマッチを取得したい場合 |
例えば、文字列に特定のパターンが含まれているかチェックするだけならpreg_match、すべての該当箇所を取得したいならpreg_match_allを使います。
パフォーマンスの考慮
大量のテキストを処理する場合:
- 正規表現をできるだけシンプルに保つ
- バックトラック(後戻り)が多くなる複雑なパターンは避ける
- 可能であれば
strposやstr_containsなど単純な文字列関数も検討する
まとめ
preg_match_allは、PHPで複数のパターンマッチを取得する際の必須関数です。
ポイント:
- すべてのマッチを配列で取得できる
- フラグで結果の構造を変更可能
- 正規表現の知識が重要
- デリミタとエスケープに注意
- UTF-8ではu修飾子を使用
正規表現は最初は難しく感じるかもしれませんが、慣れると非常に強力なツールになります。ぜひ実際のコードで試してみてください!
参考リンク
この記事が役に立ったら、ぜひシェアしてください!
