正規表現マッチって何をするもの?
まずイメージからいきます。
「正規表現マッチ」は、
文字列が「あるパターン」に当てはまるかどうかをチェックする
ための仕組みです。
「パターン」というのがポイントで、単なる「部分一致」ではなく、
- 数字だけかどうか
- メールアドレスっぽい形かどうか
- 郵便番号の形式(
123-4567)になっているか - 先頭が「ABC」で、そのあとに数字が3桁続くか
といった「形」をまとめて表現できます。
PHP では、この「パターンマッチ」に preg_match() を使います。
PHP の基本:preg_match の使い方
preg_match のシグネチャ
基本形はこうです。
int|false preg_match(string $pattern, string $subject, array &$matches = null)
PHPざっくり言うと、
$patternが「正規表現パターン」$subjectが「調べたい文字列」- 戻り値が「マッチしたら 1、しなければ 0、エラーなら false」
- 第3引数
$matchesに「マッチした内容」が入る(必要なときだけ使う)
まずは「マッチしたかどうか」だけを知りたいケースから見ていきます。
例1:数字だけかどうかチェックする
$text = "12345";
if (preg_match('/^[0-9]+$/', $text) === 1) {
echo "数字だけです";
} else {
echo "数字以外が含まれています";
}
PHPここでのポイントはパターン /^[0-9]+$/ です。
/と/が「区切り」(デリミタ)^は「先頭」[0-9]+は「0〜9 の数字が1文字以上」$は「末尾」
つまり、「先頭から末尾まで、全部が数字だけ」という意味になります。
preg_match の戻り値は 1 / 0 / false なので、
必ず === 1 で判定するのが安全です。
正規表現パターンの超基本
デリミタ(/…/)の意味
PHP の正規表現では、パターンを / で囲むのが定番です。
'/abc/'
PHPこの / は「ここからここまでがパターンですよ」という区切りです。
パターンの中に / 自体を含めたいときは、\ でエスケープします。
'/https:\/\/example\.com\//'
PHP慣れてきたら他のデリミタ(#...# など)も使えますが、
初心者のうちは /.../ だけで十分です。
よく使うメタ文字
最低限これだけ覚えておけば、かなり戦えます。
^
文字列の先頭。
$
文字列の末尾。
.
任意の1文字。
[abc]a または b または c の1文字。
[0-9]
0〜9 のどれか1文字。
+
直前のパターンが「1回以上」繰り返し。
*
直前のパターンが「0回以上」繰り返し。
?
直前のパターンが「0回か1回」。
{n,m}
直前のパターンが「n回以上 m回以下」。
これを組み合わせて「形」を表現していきます。
例題で「形」を意識してみる
例2:郵便番号(123-4567)かどうか
function isZipCode(string $text): bool
{
return preg_match('/^[0-9]{3}-[0-9]{4}$/', $text) === 1;
}
var_dump(isZipCode("123-4567")); // true
var_dump(isZipCode("12-4567")); // false
var_dump(isZipCode("1234567")); // false
PHPパターン /^[0-9]{3}-[0-9]{4}$/ は、
^先頭[0-9]{3}数字3桁-ハイフン[0-9]{4}数字4桁$末尾
という意味です。
例3:英数字とアンダースコアだけのユーザー名
function isValidUserName(string $text): bool
{
return preg_match('/^[A-Za-z0-9_]+$/', $text) === 1;
}
var_dump(isValidUserName("user_01")); // true
var_dump(isValidUserName("user-01")); // false(ハイフンは許可していない)
PHP[A-Za-z0-9_] は、「英大文字・英小文字・数字・アンダースコア」のどれか1文字、+ は「それが1文字以上続く」という意味です。
マッチした内容を取り出す($matches)
例4:メールアドレスからドメイン部分だけ抜き出す
「マッチしたかどうか」だけでなく、「どこがマッチしたか」を取りたいときは、
第3引数 $matches を使います。
$text = "contact: user@example.com";
if (preg_match('/([A-Za-z0-9._%+-]+)@([A-Za-z0-9.-]+\.[A-Za-z]{2,})/', $text, $matches) === 1) {
// $matches[0] 全体 "user@example.com"
// $matches[1] ローカル部 "user"
// $matches[2] ドメイン部 "example.com"
echo $matches[2];
}
PHPパターンの中の (...) が「キャプチャグループ」で、
マッチした部分が $matches[1], $matches[2]… に入ります。
ここは少し難易度が上がるので、
最初は「マッチしたかどうか」だけを使い、
必要になったら「取り出し」に進む、くらいで大丈夫です。
実務ユーティリティとして関数にまとめる
「パターンにマッチするかどうか」だけを返すラッパー
毎回 preg_match(...) === 1 と書くのは少し面倒なので、
ユーティリティ関数にしてしまうと読みやすくなります。
/**
* 正規表現パターンにマッチするかどうか
*
* @param string $pattern /.../ 形式のパターン
* @param string $text 調べたい文字列
* @return bool
*/
function regexMatch(string $pattern, string $text): bool
{
return preg_match($pattern, $text) === 1;
}
PHP使い方はこうなります。
if (regexMatch('/^[0-9]+$/', $input)) {
// 数字だけ
}
if (regexMatch('/^[A-Za-z0-9_]+$/', $userName)) {
// ユーザー名としてOK
}
PHP「=== 1 を中に閉じ込める」のがポイントです。
正規表現で一番ハマりやすいポイント
「なんとなく書く」と必ず迷子になる
正規表現で一番やりがちなのは、
とりあえずググって出てきたパターンをコピペして、
何をしているか分からないまま使う
という状態です。
それをやると、あとで仕様変更が来たときに、
自分でも触れなくなります。
なので、最低限ここだけは意識してほしいです。
^と$で「全体を縛る」かどうか+/*/{n,m}が「どこに」かかっているか[]の中は「1文字の集合」であること- 「何文字でもいい」のか「何文字まで許すのか」を自分で決めること
パターンを読むときは、「左から日本語に翻訳する」つもりで眺めてみてください。
まとめ:今日からの「正規表現マッチ」ユーティリティ
押さえておきたいポイントをコンパクトにまとめます。
正規表現マッチは、
preg_match($pattern, $text) === 1で「パターンに当てはまるか」を判定する- パターンは
/.../で囲み、^と$で「全体」を縛るかどうかを決める - 数字・英字・記号の「形」を表現するのに向いている
- 実務では、
isZipCodeやisValidUserNameのように「用途ごとの関数」にしておくと読みやすい
