PHP Tips | 文字列処理:検索・置換 – 正規表現マッチ

PHP PHP
スポンサーリンク

正規表現マッチって何をするもの?

まずイメージからいきます。

「正規表現マッチ」は、

文字列が「あるパターン」に当てはまるかどうかをチェックする

ための仕組みです。

「パターン」というのがポイントで、単なる「部分一致」ではなく、

  • 数字だけかどうか
  • メールアドレスっぽい形かどうか
  • 郵便番号の形式(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 で「パターンに当てはまるか」を判定する
  • パターンは /.../ で囲み、^$ で「全体」を縛るかどうかを決める
  • 数字・英字・記号の「形」を表現するのに向いている
  • 実務では、isZipCodeisValidUserName のように「用途ごとの関数」にしておくと読みやすい

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