「すべて含むかチェック」でやりたいことをイメージする
ここでやりたいのはこういう判定です。
「この文章の中に、指定した複数キーワードが“全部”含まれているか?」
例で見ると分かりやすいです。
本文: "本日は大特価セール開催中です"
キーワード一覧:
- "本日"
- "セール"
→ 両方とも含まれているので true
キーワード一覧:
- "本日"
- "セール"
- "無料"
→ "無料" が含まれていないので false
さっきやった「いずれかを含むか」は OR 条件でしたが、
今回は「全部含んでいるか」という AND 条件になります。
業務だと、例えばこんな場面で使います。
- 検索条件として「この3つの単語をすべて含む記事だけ」を抽出したい
- ログの1行に、「ユーザーID」と「エラーコード」の両方が含まれている行だけを拾いたい
- メール本文に、「必須の注意文言」が全部入っているか確認したい
ここをユーティリティにしておくと、検索・チェック系の処理がかなり書きやすくなります。
ベースになるのは「1つのキーワードの部分一致チェック」
まずは単体版の「含まれているか」を思い出します。
function contains(string $haystack, string $needle): bool
{
return mb_strpos($haystack, $needle, 0, 'UTF-8') !== false;
}
PHP$haystackが「探される側」$needleが「探すキーワード」- 見つかれば true、見つからなければ false
「すべて含むかチェック」は、これを複数キーワードに対して AND 条件で回すイメージです。
ロジックを言葉で分解する
「すべて含むか」は、こう考えられます。
- キーワード一覧(配列)を1つずつ取り出す
- そのキーワードが含まれているか(contains)をチェックする
- 1つでも「含まれていない」ものがあったら、全体として false
- 最後まで全部「含まれている」なら true
さっきの「いずれかを含むか」が「どれか1つでも見つかったら true」だったのに対して、
今回は「1つでも見つからなかったら false」です。
実装例:allContains ユーティリティ
すべて含むかチェックの基本形
/**
* すべてのキーワードを含むかチェック
*
* @param string $haystack 調べたい文字列
* @param string[] $keywords キーワード配列
* @return bool
*/
function allContains(string $haystack, array $keywords): bool
{
foreach ($keywords as $keyword) {
if ($keyword === '') {
// 空文字をどう扱うかは仕様次第。ここではスキップ。
continue;
}
if (mb_strpos($haystack, $keyword, 0, 'UTF-8') === false) {
// このキーワードが含まれていない時点でアウト
return false;
}
}
// すべてのキーワードが含まれていた
return true;
}
PHPポイントはここです。
!== falseではなく=== falseを見ている- 「見つからなかったら即 false を返す」ことで AND 条件を表現している
「いずれかを含むか」のときは「見つかったら即 true」でしたが、
今回はその逆です。
例題で動きをしっかりイメージする
例1:記事本文がすべてのキーワードを含むか
$keywords = [
"PHP",
"ユーティリティ",
"文字列",
];
$text = "このブログでは、PHP の文字列ユーティリティについて解説します。";
var_dump(allContains($text, $keywords)); // true
PHPこの場合、
- “PHP” → 含まれている
- “ユーティリティ” → 含まれている
- “文字列” → 含まれている
なので true になります。
$keywords = [
"PHP",
"ユーティリティ",
"データベース",
];
var_dump(allContains($text, $keywords)); // false
PHP今度は “データベース” が含まれていないので、途中で false が返されます。
例2:ログ1行に必須情報が全部入っているか
$mustWords = [
"user_id=",
"error_code=",
];
$line1 = "[ERROR] user_id=123 error_code=500 message=...";
$line2 = "[ERROR] user_id=123 message=...";
var_dump(allContains($line1, $mustWords)); // true
var_dump(allContains($line2, $mustWords)); // false
PHP$line2 には error_code= がないので、
「必須情報が欠けているログ」として扱えます。
大文字・小文字を無視したい場合
そのままだと “ERROR” と “error” は別物
英字のチェックで、「大文字・小文字を区別したくない」ことはよくあります。
$keywords = ["error", "user_id="];
$line = "[ERROR] user_id=123";
PHPこのまま allContains を使うと、”error” は含まれていないと判定されます。
大文字・小文字を無視する allContainsIgnoreCase
両方を小文字にそろえてから検索する版を用意しておくと便利です。
function allContainsIgnoreCase(string $haystack, array $keywords): bool
{
$haystackLower = mb_strtolower($haystack, 'UTF-8');
foreach ($keywords as $keyword) {
if ($keyword === '') {
continue;
}
$keywordLower = mb_strtolower($keyword, 'UTF-8');
if (mb_strpos($haystackLower, $keywordLower, 0, 'UTF-8') === false) {
return false;
}
}
return true;
}
PHPこれなら、
$keywords = ["error", "user_id="];
$line1 = "[ERROR] user_id=123";
$line2 = "[Error] user_id=123";
$line3 = "[INFO] user_id=123";
var_dump(allContainsIgnoreCase($line1, $keywords)); // true
var_dump(allContainsIgnoreCase($line2, $keywords)); // true
var_dump(allContainsIgnoreCase($line3, $keywords)); // false
PHPのように、「ERROR / Error / error」を同じものとして扱えます。
設計上の細かいポイントを少し深掘りする
空配列のときは true か false か
$keywords が空配列 [] のとき、どう扱うかは仕様次第です。
- 「チェックするものが何もないので true」
- 「条件が不正なので false」
数学的には「空の AND は true」なので、
上の実装だと true になります(ループに一度も入らず、そのまま return true)。
多くの実務ではそれで困ることは少ないですが、
気になるなら「空配列なら false にする」など、最初に条件を足してもいいです。
if ($keywords === []) {
return false; // など
}
PHPキーワードが多いときのパフォーマンス
allContains は、キーワードの数だけ mb_strpos を呼びます。
- キーワードが数個〜数十個程度なら、ほぼ問題なし
- 数百〜数千になると、さすがに重くなる可能性がある
その場合は、全文検索エンジンやインデックスを使うべき領域なので、
まずは「業務アプリの簡易チェック」レベルなら、この実装で十分です。
まとめ:今日からの「すべて含むかチェック」ユーティリティ
押さえておきたいポイントをコンパクトにまとめます。
- 「すべて含むか」は、複数キーワードに対する AND 条件。
1つでも「含まれていない」ものがあれば false。 - UTF-8 前提なら、
mb_strposを使って実装するのが安全。 - 大文字・小文字を無視したい場合は、両方を小文字にそろえてから検索する。
- 実務では、
allContains()/allContainsIgnoreCase()のようなユーティリティ関数にしておくと、
検索条件や必須文言チェックをシンプルに書ける。
ベースになる実装は、まずはこれで十分です。
function allContains(string $haystack, array $keywords): bool
{
foreach ($keywords as $keyword) {
if ($keyword === '') {
continue;
}
if (mb_strpos($haystack, $keyword, 0, 'UTF-8') === false) {
return false;
}
}
return true;
}
PHP