【PHP8.x】substr_count関数の使い方

substr_count関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

substr_count関数は、指定された文字列(haystack)の中に、特定の文字列(needle)が何回出現するかをカウントする関数です。この関数は、大文字と小文字を区別してカウントを行います。例えば、長い文章中に特定のキーワードがいくつ含まれているかを調べたい場合や、ログデータから特定のエラーメッセージの発生頻度を知りたい場合などに役立ちます。

この関数は、以下の引数を取ります。 最初の引数 $haystack には、検索の対象となる元の文字列を指定します。 次の引数 $needle には、$haystack の中で探したい部分文字列を指定します。 オプションの3番目の引数 $offset には、文字列のどの位置から検索を開始するかを整数で指定します。デフォルト値は 0 で、文字列の先頭から検索を開始します。 オプションの4番目の引数 $length には、$offset で指定した位置から、どのくらいの長さの範囲内で検索を行うかを整数で指定します。この引数を省略すると、$offset から文字列の最後までが検索対象となります。

戻り値としては、$haystack 内で $needle が見つかった回数を整数で返します。$needle が全く見つからなかった場合は 0 を返します。検索はバイト単位で行われるため、日本語のようなマルチバイト文字を扱う際には、文字数ではなくバイト数で処理されることに注意が必要です。この関数を利用することで、文字列内での部分文字列の出現頻度を手軽に把握することができます。

構文(syntax)

1<?php
2$text = "apple banana apple orange apple";
3$sub = "apple";
4$count = substr_count($text, $sub);
5echo $count; // 3 が出力されます。
6?>

引数(parameters)

string $haystack, string $needle, int $offset = 0, ?int $length = null

  • string $haystack: 検索対象となる文字列
  • string $needle: 検索する部分文字列
  • int $offset = 0: 検索を開始する位置(デフォルトは文字列の先頭)
  • ?int $length = null: 検索する文字列の長さ(デフォルトは残りの全文字列)

戻り値(return)

int

指定された文字列の中に、検索対象の文字列がいくつ含まれているかを整数で返します。

サンプルコード

PHP substr_countでマルチバイト文字をカウントする

1<?php
2
3/**
4 * substr_countの基本的な使い方と、マルチバイト文字列における注意点を示すサンプルコードです。
5 * PHPの標準関数には「mb_substr_count」は存在しませんが、
6 * それを求める意図(マルチバイト文字列における文字単位の出現回数カウント)に応えるため、
7 * カスタム関数「mb_substr_count_char_aware」を併せて提供します。
8 */
9
10// PHPの内部文字エンコーディングをUTF-8に設定することを推奨します。
11// これにより、mb_*関数が正しく動作します。
12mb_internal_encoding('UTF-8');
13
14// --- 1. substr_countの基本的な使い方 (ASCII文字列) ---
15$haystackAscii = "Hello world, hello PHP!";
16$needleAscii = "hello";
17
18// substr_countは、指定された部分文字列が何回出現するかをカウントします。
19// デフォルトでは大文字・小文字を区別します。
20$countAsciiCaseSensitive = substr_count($haystackAscii, $needleAscii);
21echo "ASCII文字列 (大文字小文字区別): '$needleAscii' は '$haystackAscii' に {$countAsciiCaseSensitive} 回出現します。\n"; // 出力: 1
22
23// 大文字・小文字を区別せずにカウントしたい場合は、文字列を変換してからカウントします。
24$countAsciiCaseInsensitive = substr_count(mb_strtolower($haystackAscii), mb_strtolower($needleAscii));
25echo "ASCII文字列 (大文字小文字区別なし): '$needleAscii' は '$haystackAscii' に {$countAsciiCaseInsensitive} 回出現します。\n\n"; // 出力: 2
26
27
28// --- 2. substr_countのマルチバイト文字列に対する動作 ---
29// substr_countはバイト単位で検索するため、マルチバイト文字(例: 日本語、絵文字)では
30// 予期せぬ結果になることがあります。
31$haystackMultiByte = "こんにちは、世界!こんにちは、PHP!";
32$needleMultiByte = "こんにちは"; // この文字列はUTF-8で5文字(15バイト)です。
33
34// substr_countは「こんにちは」というバイト列の出現回数をカウントします。
35// この例では、たまたま期待通りの結果(2回)となりますが、
36// 部分的なバイト列が別の文字と一致する場合など、常に文字単位で動作するわけではありません。
37$countMultiByteDirect = substr_count($haystackMultiByte, $needleMultiByte);
38echo "マルチバイト文字列 (substr_count): '$needleMultiByte' は '$haystackMultiByte' に {$countMultiByteDirect} 回出現します。\n\n"; // 出力: 2
39
40
41// --- 3. キーワード「mb_substr_count」への対応 (マルチバイト文字対応のカスタムカウント関数) ---
42// PHPには標準でmb_substr_count関数は存在しません。
43// 以下のカスタム関数は、マルチバイト文字列の文字単位での出現回数を正確にカウントします。
44// これは、mb_strpos() をループで利用して実現します。
45
46/**
47 * マルチバイト文字列における部分文字列の出現回数を文字単位でカウントします。
48 * PHPの標準substr_countがバイト単位でカウントするのに対し、この関数は文字単位でカウントします。
49 *
50 * @param string      $haystack 検索対象の文字列。
51 * @param string      $needle   検索する部分文字列。
52 * @param int         $offset   検索開始位置の文字オフセット。負の値は文字列の終わりからのオフセット。
53 * @param int|null    $length   検索する文字列の最大長(文字数)。nullの場合は文字列の最後まで。
54 * @param string|null $encoding 文字エンコーディング。nullの場合はmb_internal_encoding()を使用。
55 * @return int 出現回数。
56 */
57function mb_substr_count_char_aware(
58    string $haystack,
59    string $needle,
60    int $offset = 0,
61    ?int $length = null,
62    ?string $encoding = null
63): int {
64    // 空のneedleは無限にマッチするため、0を返します。
65    if ($needle === '') {
66        return 0;
67    }
68
69    // デフォルトエンコーディングを設定
70    $encoding = $encoding ?? mb_internal_encoding();
71
72    // offsetとlengthを文字単位で調整し、検索対象の文字列範囲を特定します。
73    $haystackLength = mb_strlen($haystack, $encoding);
74    if ($offset < 0) {
75        $offset = max(0, $haystackLength + $offset);
76    }
77    if ($length !== null) {
78        $length = max(0, min($length, $haystackLength - $offset));
79    } else {
80        $length = $haystackLength - $offset;
81    }
82
83    // 検索範囲を切り出し、この範囲内で部分文字列を検索します。
84    $searchString = mb_substr($haystack, $offset, $length, $encoding);
85
86    $count = 0;
87    $needleLength = mb_strlen($needle, $encoding);
88    $currentOffset = 0; // searchString内での現在の検索開始文字オフセット
89
90    // mb_strposを使って、見つかるたびにその次から検索を再開します。
91    while (($pos = mb_strpos($searchString, $needle, $currentOffset, $encoding)) !== false) {
92        $count++;
93        // 見つかった部分文字列の直後から次の検索を開始します(重複カウントなし)。
94        $currentOffset = $pos + $needleLength;
95    }
96
97    return $count;
98}
99
100// --- カスタム関数 mb_substr_count_char_aware の使用例 ---
101$haystackMultiByte = "こんにちは、世界!こんにちは、PHP!";
102$needleMultiByte = "こんにちは";
103$needleEmoji = "🍎"; // 絵文字もマルチバイト文字です
104
105// 文字単位で正確にカウント
106$countCharAware = mb_substr_count_char_aware($haystackMultiByte, $needleMultiByte);
107echo "マルチバイト文字列 (mb_substr_count_char_aware): '$needleMultiByte' は '$haystackMultiByte' に {$countCharAware} 回出現します。\n"; // 出力: 2
108
109$haystackWithEmoji = "🍎バナナ🍎りんご🍎みかん";
110$countEmoji = mb_substr_count_char_aware($hay haystackWithEmoji, $needleEmoji);
111echo "絵文字を含む文字列 (mb_substr_count_char_aware): '$needleEmoji' は '$haystackWithEmoji' に {$countEmoji} 回出現します。\n"; // 出力: 3
112
113// offsetとlengthを指定した使用例
114// 5文字目から検索を開始します(「こんにちは」の「は」の後から)。
115$countWithOffset = mb_substr_count_char_aware($haystackMultiByte, $needleMultiByte, 5);
116echo "マルチバイト文字列 (mb_substr_count_char_aware, offset=5): '$needleMultiByte' は '$haystackMultiByte' に {$countWithOffset} 回出現します。\n"; // 出力: 1
117?>

PHPのsubstr_count関数は、指定された文字列($haystack)の中に、特定の部分文字列($needle)が何回出現するかを数えるための関数です。検索を開始する位置を$offset、検索する最大長を$lengthで指定でき、見つかった回数を整数値(int)で返します。この関数は、デフォルトでは大文字・小文字を区別してカウントし、区別しない場合は検索対象と部分文字列を事前に小文字に変換する必要があります。

しかし、substr_countは文字列をバイト単位で処理するため、日本語や絵文字などのマルチバイト文字を含む文字列では、意図しない結果となることがあります。例えば「こんにちは」のような文字列の場合、バイト列として一致するかどうかで判断されるため、文字単位での正確なカウントは保証されません。

PHPには標準でmb_substr_countという関数は存在しません。そのため、マルチバイト文字列において文字単位で正確な出現回数を数えたい場合は、カスタム関数を自作する必要があります。サンプルコードで提供されているmb_substr_count_char_aware関数は、この目的のために設計されており、mb_strposなどのマルチバイト対応関数を組み合わせて文字単位でのカウントを実現しています。このカスタム関数を用いることで、日本語や絵文字を含む文字列でも、指定された部分文字列の出現回数を文字として正確に把握できます。マルチバイト関連関数を正しく機能させるため、mb_internal_encodingをUTF-8などに設定しておくことを推奨します。

substr_count関数は指定された部分文字列の出現回数をカウントしますが、デフォルトで大文字・小文字を区別します。大文字・小文字を区別しない場合は、mb_strtolower関数などで事前に文字列を変換してください。特に注意が必要なのは、この関数が文字列をバイト単位で検索する点です。日本語や絵文字などのマルチバイト文字列では、期待する文字単位でのカウントではなく、バイト列の一致を数えるため、意図しない結果となることがあります。PHPには標準のmb_substr_count関数は存在しません。マルチバイト文字列を文字単位で正確に数えたい場合は、サンプルコードに示されているようにmb_strposなどを利用したカスタム関数を実装する必要があります。また、mb_internal_encoding('UTF-8')などを用いて、PHPの内部文字エンコーディングを適切に設定することで、マルチバイト関連関数が正しく動作し、より安全にコードを利用できます。

PHP substr_countで大文字小文字を区別せずにカウントする

1<?php
2
3/**
4 * substr_count を使用して、文字列内の部分文字列の出現回数を大文字小文字を区別せずにカウントします。
5 *
6 * @param string $haystack 検索対象の文字列。
7 * @param string $needle 検索する部分文字列。
8 * @return int 部分文字列の出現回数。
9 */
10function countSubstrCaseInsensitive(string $haystack, string $needle): int
11{
12    // 検索対象の文字列と検索する部分文字列の両方を小文字に変換します。
13    // これにより、substr_count が大文字小文字を区別せずに検索を行うことができます。
14    $lowerHaystack = strtolower($haystack);
15    $lowerNeedle = strtolower($needle);
16
17    // 小文字に変換された文字列と部分文字列を使って、substr_count で出現回数をカウントします。
18    return substr_count($lowerHaystack, $lowerNeedle);
19}
20
21// --- 使用例 ---
22
23$text = "Hello World! PHP is great, and PHP 8 is even better. Long live PHP!";
24$searchText = "php";
25
26echo "元の文字列: " . $text . "\n";
27echo "検索する部分文字列 (大文字小文字を区別しない): '" . $searchText . "'\n";
28
29// countSubstrCaseInsensitive 関数を呼び出し、出現回数を取得します。
30$count = countSubstrCaseInsensitive($text, $searchText);
31
32echo "出現回数: " . $count . "\n"; // 期待される出力: 3 (PHP, PHP, PHP!)
33
34echo "\n--- 別の例 ---\n";
35
36$text2 = "Apple, apple, and APPLES.";
37$searchText2 = "APPLe";
38echo "元の文字列: " . $text2 . "\n";
39echo "検索する部分文字列 (大文字小文字を区別しない): '" . $searchText2 . "'\n";
40$count2 = countSubstrCaseInsensitive($text2, $searchText2);
41echo "出現回数: " . $count2 . "\n"; // 期待される出力: 3
42
43?>

PHPのsubstr_count関数は、指定した文字列($haystack)の中に、特定の部分文字列($needle)が何回出現するかを数え、その回数を整数(int)で返す関数です。この関数は引数として、検索対象の文字列と検索したい部分文字列を必須で受け取ります。オプションとして、検索を開始する位置($offset)や検索範囲の長さ($length)も指定できますが、デフォルトでは大文字と小文字を区別して検索を行います。

今回のサンプルコードでは、substr_count関数を利用して、部分文字列の出現回数を大文字小文字を区別せずにカウントする方法を示しています。countSubstrCaseInsensitiveという関数内で、まず検索対象の文字列$haystackと検索する部分文字列$needleの両方をstrtolower関数で小文字に変換しています。これにより、元の文字列中の「PHP」と検索文字列の「php」のように、大文字小文字の違いがある場合でも同じものとして認識されるようになります。その後、小文字に変換されたこれらの文字列をsubstr_count関数に渡すことで、大文字小文字を無視した出現回数を正確に取得できるようになります。

例えば、「Hello World! PHP is great, and PHP 8 is even better. Long live PHP!」という文字列から「php」を大文字小文字を区別せずに検索すると、結果として「PHP」が3回出現しているとカウントされます。このように、事前に文字列を小文字に統一する前処理を行うことで、より柔軟な文字列検索を実現できます。

substr_count関数は、デフォルトで大文字と小文字を区別して部分文字列の出現回数をカウントします。そのため、サンプルコードではstrtolower関数を用いて検索対象と検索する部分文字列の両方を事前に小文字に変換し、大文字小文字を区別しない検索を実現しています。この前処理を行わない場合、「PHP」と「php」は異なる文字列として扱われ、期待通りの結果が得られませんので注意が必要です。また、日本語のようなマルチバイト文字を扱う場合は、strtolowerの代わりにmb_strtolowerなどのマルチバイト対応関数を使用し、文字エンコーディングを考慮することが重要です。substr_countの第三引数$offsetや第四引数$lengthを指定すると、文字列の特定範囲内でのみ検索を行うことも可能です。

関連コンテンツ

【PHP8.x】substr_count関数の使い方 | いっしー@Webエンジニア