JavaScriptの文字列はサブ文字列を含む:完全ガイド

2026年2月13日

ある文字列が別の文字列を含むかどうかのチェック(部分文字列検索)は、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 });  // true

2026年の提言

  • デフォルト インクルード() 明瞭さのために
  • 大文字小文字を無視するための正規表現ではなく、大文字小文字を正規化する。
  • 正規表現パターンのキャッシュ
  • 実際のワークロードを測定する(マイクロベンチマークへのこだわりを避ける)
  • ライブラリ (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処理、ユーザー生成データなどのエッジケースを考慮することで、弾力性とスケーラビリティの両方を備えたコードを実現できる。.

カーマテック このような基礎的な細部への配慮が、信頼性、スピード、保守性の向上に直接貢献します。.