ある文字列が別の文字列を含むかどうかのチェック(部分文字列検索)は、JavaScript開発において最も一般的な文字列操作の1つです。ユーザー入力の検証、React/Vueアプリでの検索フィルタの実装、APIレスポンスの解析、オートコンプリート機能の構築、Node.jsでのログ処理など、このチェックはあらゆるところで登場します。.
2026年2月現在、ECMAScript 2026 (ES2026)が現在または間近に迫っている標準である(最終版は2026年半ば)。コア String.prototype 部分文字列の検出方法 includes()、indexOf()、search(), および正規表現 .test() - は、ES2015/ES6以降も変更されていません。V8(Node22+/Chrome130+)、SpiderMonkey(Firefox135+)、JavaScriptCore(Safari19+)などのエンジンでは、パフォーマンス、可読性、Unicodeの正しさ、最新のベストプラクティスに重点を置いています。.
このガイドでは、あらゆる実用的なテクニック、2026年におけるパフォーマンスの現実、エッジケース、セキュリティの考慮点、そして本番ですぐに使える推奨事項を網羅している。.
なぜサブストリングチェックはどこにでもあるのか
- UI/UX:ライブ検索、タグフィルタリング、フォームバリデーション
- バックエンド:ログ解析、ルートマッチング、コンテンツモデレーション
- データ処理:文字列/オブジェクトの配列のフィルタリング
- 安全:悪意のあるパターン(XSSペイロード、禁句)の検出
- パフォーマンス重視:オートコンプリート(数百万件/秒)、リアルタイムモニタリング
ループや大規模なデータセットでは、小さな非効率があっという間に増殖する。.
1.現代のスタンダード: String.prototype.includes()
ES2015から採用された手法で、クリーンで、意図が明らかになり、高度に最適化されている。.
署名
js str.includes(searchString, position?)
searchString:検索する部分文字列(文字列に強制される。)位置(オプション): 開始インデックス (デフォルト 0; ≥0 でクランプ)
リターン: ブーリアン
例
js
const phrase = "2026年のJavaScriptはパワフルで速い";
console.log(phrase.includes("2026"));; // 真
console.log(phrase.includes("2025"));; // 偽
console.log(phrase.includes("script"));; // 真(大文字と小文字を区別する)
console.log(phrase.includes(""));; // true ←空は常にマッチする
console.log(phrase.includes("fast", 30));; // 真
console.log(phrase.includes("fast", 40));; // 偽なぜ好むのか インクルード() 2026年に?
- 最大限の可読性:“それが含まれているか?”を明確に表現する。”
- エンジン最適化(V8/SpiderMonkeyは高速なBoyer-Mooreまたは双方向アルゴリズムを使用します。)
- ユニバーサルサポート:2017年以降、モダンブラウザ/ノードで100%をサポート
デメリット
- ブール値のみ(インデックスなし)
- 常に大文字と小文字を区別する
2.クラシック&ポジションアウェア: String.prototype.indexOf()
ES6以前の主力選手 - ロケーションが必要な時には今でも素晴らしい。.
署名
js str.indexOf(searchString, fromIndex?)
リターン最初のインデックス ≥ fromIndex または -1
存在チェック
js
if (phrase.indexOf("2026") !== -1) { { { (phrase.indexOf("2026") !== -1) /* 見つかった */ }
// 好みのスタイル
if (phrase.indexOf("2026") >= 0) {。 /* 見つかった */ }すべての発生を見つける
js
let positions = [];
let idx = -1;
while ((idx = phrase.indexOf("a", idx + 1)) !== -1) { .
positions.push(idx);
}
console.log(positions);; // [1, 4, 11, ...]2026年の現実: インクルード() そして indexOf() ブーリアン・チェックのスピードはほぼ同じである。 インクルード() インデックスが必要な場合を除き、わかりやすくするために。.
3.大文字小文字を区別しないチェック(実世界で最も頻繁に必要とされるもの)
includes()/indexOf()には、大文字小文字を区別しないネイティブ・フラグが存在しない。.
ベストプラクティス2026:ケースの正規化
js
function containsIgnoreCase(text, term) {
if (text == null || term == null) return false;
return text.toLowerCase().includes(term.toLowerCase());
// またはロケール対応(本番環境では推奨):
// text.toLocaleLowerCase('en').includes(term.toLocaleLowerCase('en'));;
}
console.log(containsIgnoreCase(phrase, "POWERFUL"));; // 真なぜ toLowerCase() 常勝
- リテラル検索では正規表現より高速
- 最近のGCでは仮設ストリングが安い
- 正規表現のコンパイル/エスケープのオーバーヘッドを回避
ロケールの注意 - トルコ語"I".toLowerCase() → "ı")または他の言語が驚くかもしれません。使用言語 toLocaleLowerCase() 国際化が重要な場合は、ロケールを明示的に指定します。.
正規表現の代替(柔軟だが遅い)
js
function containsIgnoreCaseRegex(text, term) { 以下のようになります。
if (!term) return true;;
// 用語がユーザーから来た場合は、特殊文字をエスケープする。
const escaped = term.replace(/[.*+?^${}()|[¬]/g, '¬$&');
return new RegExp(escaped, 'i').test(text);
}あるいはワンライナー(信頼できる期間のみ):
js /2026/i.test(フレーズ);; // 真
正規表現を選択するタイミング
- 単語の境界が必要
\(英語)) - 交替 (
猫|犬) - ルックアラウンドやその他のパターン
パフォーマンスのヒント:コンパイル正規表現 かつて アウトサイドループ/ホットパス.
4.その他の方法とその使用時期
String.prototype.search(正規表現)
最初のマッチインデックスまたは-1. .現在ではほとんど使われていない。インクルード()または.test()が明確になった。.String.prototype.match()/matchAll()
単純な存在ではなく、マッチを抽出するために。.startsWith()/endsWith()(ES2015)
特殊なチェック - 接頭辞/接尾辞をより速く。.
js
フレーズ.startWith("Java");; // 真
phrase.endsWith("fast");; // 真5.2026年の性能 エンジン
おおよその相対速度(V8/Node 22+、大きな文字列〜10k文字、リテラル検索):
| 方法 | レル速度 | 最適 | 備考 |
インクルード() 文字 | 1.0× | 単純なイエス/ノー | トップ・チョイス |
indexOf() | ~1.0-1.02× | インデックスまたは複数の検索が必要 | 以下は同系列 |
toLowerCase() + includes() | 0.65-0.80× | 大文字小文字を区別しないリテラル | 2本の臨時ストリングだが速い |
/literal/i.test() | 0.25-0.45× | ケース・インセンスまたはバウンダリー | 正規表現のオーバーヘッド |
new RegExp(escaped, 'i').test() | 0.20-0.40× | ダイナミック/サニタイズド入力 | エスケープコスト+正規表現 |
主な収穫:用途 インクルード() リテラル用。正規表現が必要な場合を除き、大文字と小文字の区別は無視する。正規表現は2-5倍遅いが、きついループでなければ許容範囲。.
6.エッジケースとゴッチャ(2026年重大事件)
includes("") → true(空の部分文字列はどこにでもマッチする)null/未定義干し草/針 → タイプエラー- サロゲートペアと絵文字 → 正しく扱われる (UTF-16)
js "Hello ግ 2026".includes("ግ"); // true - ネガティブ
位置0 として扱う - 非常に長い文字列 → エンジンは効率的なアルゴリズムを使用(平均O(n)
- ユーザー入力 決して エスケープせずに生のユーザー文字列から正規表現を構築する。
7.プロダクション・ヘルパーとベストプラクティス
ヌルセーフユーティリティ(TypeScriptフレンドリー):
ts
function contains(
haystack: string | null | undefined,
needle: string | null | undefined,
options: { ignoreCase?: boolean; from?: number } = {}
): boolean {
if (haystack == null || needle == null) return false;
const { ignoreCase = false, from = 0 } = options;
const h = ignoreCase ? haystack.toLowerCase() : haystack;
const n = ignoreCase ? needle.toLowerCase() : needle;
return h.includes(n, from);
}
// Usage
contains("JavaScript 2026", "script", { ignoreCase: true }); // true2026年の提言
- デフォルト
インクルード()明瞭さのために - 大文字小文字を無視するための正規表現ではなく、大文字小文字を正規化する。
- 正規表現パターンのキャッシュ
- 実際のワークロードを測定する(マイクロベンチマークへのこだわりを避ける)
- ライブラリ (lodash
_.includes, Fuse.js)は、あいまい検索や高度な検索が必要な場合にのみ使用する。
結論
2026年になっても、JavaScriptで文字列が部分文字列を含むかどうかをチェックするのは、高度に最適化されたAPIによって、見かけによらず簡単な操作のままだ。. String.prototype.includes() 明瞭さ、パフォーマンス、そして表現力豊かな可読性を提供する。大文字小文字を区別しないチェックでは toLowerCase() (または必要に応じてロケールを意識した代替) は、信頼性が高く効率的なアプローチを提供する。正規表現は、リテラルマッチを超えるパターンレベルの柔軟性が必要な場合に使用する。.
開発者がよく使うパターン
- リテラル・ブーリアン・チェック → (英語
str.includes(サブ) - 位置/インデックス → を持つ
str.indexOf(sub) >= 0 - 無視する場合
str.toLowerCase().includes(sub.toLowerCase()) - 複雑なニーズ → キャッシュ
RegExp.test()
適切な方法を選択し、空の値、NULL入力、Unicode処理、ユーザー生成データなどのエッジケースを考慮することで、弾力性とスケーラビリティの両方を備えたコードを実現できる。.
カーマテック このような基礎的な細部への配慮が、信頼性、スピード、保守性の向上に直接貢献します。.