PHP Tips | 文字列処理:検索・置換 – 部分一致チェック

PHP PHP
スポンサーリンク

「部分一致チェック」でやりたいことをまずイメージする

やりたいことはシンプルです。

「ある文字列の中に、探したいキーワードが含まれているかどうか」を調べたい。

例えば、こういう判定です。

本文: "本日は晴天なり"
キーワード: "晴天" → 含まれている(true)
キーワード: "雨"   → 含まれていない(false)

業務だと、こんな場面でよく使います。

  • エラーメッセージに特定の文言が含まれているかチェックする
  • 入力値に禁止ワードが含まれていないかチェックする
  • ログの1行に、特定のIDやタグが含まれているか調べる

この「含まれているかどうか」を、PHP でどう書くかを整理していきます。


基本:strpos で「含まれているか」を調べる

strpos の動きと注意点

まずは、PHP の基本関数 strpos() から。

int|false strpos(string $haystack, string $needle)
PHP
  • 第1引数:探される側(大きい文字列)
  • 第2引数:探す側(キーワード)
  • 戻り値:見つかった位置(0以上の整数)/見つからなければ false

例を見た方が早いです。

$text = "本日は晴天なり";

var_dump(strpos($text, "晴天")); // int(9) など(位置は環境依存・マルチバイトでズレることも)
var_dump(strpos($text, "雨"));   // bool(false)
PHP

ここで一番大事な注意点がこれです。

見つかった位置が「0」のときもある。
0 は「先頭で見つかった」という意味。
でも、if (strpos(...)) と書くと「false と同じ扱い」になってしまう。

つまり、こう書くとバグります。

if (strpos($text, "本日")) {
    // ここには来ない(0 は false とみなされる)
}
PHP

なので、必ず「=== false かどうか」で判定するのが鉄則です。

$pos = strpos($text, "本日");

if ($pos === false) {
    // 見つからない
} else {
    // 見つかった(先頭かもしれないし、途中かもしれない)
}
PHP

ここを雑に書くと、初心者が一番ハマる「部分一致チェックの罠」になります。


実務で使いやすい「含まれているかどうか」ユーティリティ

true / false だけ返す関数にしてしまう

毎回 strpos の戻り値と === false を意識するのは面倒なので、
「含まれているかどうか」だけを返す関数にしてしまうと楽です。

/**
 * 部分一致チェック:$needle が $haystack に含まれているか
 *
 * @param string $haystack 探される側
 * @param string $needle   探す文字列
 * @return bool
 */
function contains(string $haystack, string $needle): bool
{
    return strpos($haystack, $needle) !== false;
}
PHP

使い方はとてもシンプルになります。

$text = "本日は晴天なり";

if (contains($text, "晴天")) {
    echo "晴天が含まれています";
}

if (!contains($text, "雨")) {
    echo "雨は含まれていません";
}
PHP

!== false を中に閉じ込めてしまう」のがポイントです。
これで、呼び出し側は「含まれているかどうか」だけを意識すればよくなります。


日本語・マルチバイト文字をちゃんと扱うなら mb_strpos

strpos の弱点と mb_strpos

strpos は「バイト位置」で動きます。
UTF-8 の日本語を扱うときに、「文字数」としての位置がズレることがあります。

「含まれているかどうか」だけなら、
false かどうかだけ見ればいいので、実害はあまりありませんが、
マルチバイト対応としては mb_strpos() を使う方がきれいです。

int|false mb_strpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null)
PHP

使い方はほぼ同じで、第4引数に 'UTF-8' を指定します。

$pos = mb_strpos($text, "晴天", 0, 'UTF-8');
PHP

これを使ったユーティリティはこう書けます。

function contains(string $haystack, string $needle): bool
{
    return mb_strpos($haystack, $needle, 0, 'UTF-8') !== false;
}
PHP

UTF-8 前提のプロジェクトなら、
「文字列検索は最初から mb_strpos に寄せる」と決めてしまうのがおすすめです。


例題でイメージを固める

例1:禁止ワードチェック

ユーザーの入力に、禁止ワードが含まれていないかチェックする例です。

$ngWords = [
    "禁止ワードA",
    "禁止ワードB",
];

$input = $_POST['comment'] ?? '';

foreach ($ngWords as $ng) {
    if (contains($input, $ng)) {
        echo "禁止ワードが含まれています: {$ng}";
        // エラー処理へ
    }
}
PHP

ここでは「どこに含まれているか」は気にせず、
「含まれているかどうか」だけを見ています。

例2:ログの1行から特定のタグを探す

$line = "[INFO] user_id=123 action=login";

if (contains($line, "user_id=123")) {
    // このユーザーのログとして扱う
}
PHP

ログ解析や簡易フィルタなどで、
「特定の文字列を含む行だけを処理したい」ときに、そのまま使えます。


大文字・小文字を無視したい場合

str_contains 的な「ケースインセンシティブ版」を自作する

英字の検索で、「大文字・小文字を区別したくない」ことも多いです。

$text = "Hello World";

contains($text, "hello"); // false(そのままだと見つからない)
PHP

こういうときは、両方を小文字にそろえてから検索する、という手があります。

function containsIgnoreCase(string $haystack, string $needle): bool
{
    $haystack = mb_strtolower($haystack, 'UTF-8');
    $needle   = mb_strtolower($needle, 'UTF-8');

    return mb_strpos($haystack, $needle, 0, 'UTF-8') !== false;
}
PHP

これなら、

$text = "Hello World";

containsIgnoreCase($text, "hello"); // true
containsIgnoreCase($text, "WORLD"); // true
PHP

のように、「大文字・小文字を無視した部分一致チェック」ができます。


まとめ:今日からの「部分一致チェック」ユーティリティ

押さえておきたいポイントをコンパクトにまとめます。

  • strpos / mb_strpos は、「見つかった位置」か「false」を返す。
  • 0 も「見つかった」という意味なので、if (strpos(...)) はNG。
    必ず !== false で判定する。
  • 実務では、「含まれているかどうか」だけを返す contains() のようなユーティリティ関数にしてしまうと、安全で読みやすい。
  • UTF-8 前提なら、mb_strpos を使う版にしておくと安心。

実務ユーティリティとしては、まずはこれ一つをプロジェクトに置いておくとかなり使い回せます。

function contains(string $haystack, string $needle): bool
{
    return mb_strpos($haystack, $needle, 0, 'UTF-8') !== false;
}
PHP

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