【JavaScript】substring の使い方|文字列の切り出し・slice との違い・indexOf との組み合わせ・実務パターンまで解説

【JavaScript】substring の使い方|文字列の切り出し・slice との違い・indexOf との組み合わせ・実務パターンまで解説 JavaScript

substring は文字列の指定した範囲を切り出して新しい文字列を返すメソッドです。元の文字列は変更されません。似たメソッドに slice がありますが、引数の扱いにいくつかの違いがあります。この記事では substring の基本から slice との使い分け、indexOf との組み合わせまで詳しく解説します。

この記事でわかること
・substring の基本構文と動作
・引数の省略・範囲外・負の値のときの挙動
・slice との違い(負のインデックス・引数の入れ替え)
・非推奨の substr との比較
・indexOf / lastIndexOf との組み合わせ
・ドメイン抽出・マスキング・文字数制限の実務パターン
スポンサーリンク

substring の基本構文

構文
const result = str.substring(indexStart, indexEnd);
// indexStart: 切り出し開始位置(この位置を含む)
// indexEnd:   切り出し終了位置(この位置は含まない・省略可)
// 戻り値:    切り出した新しい文字列(元の文字列は変更されない)
基本例
const str = "JavaScript";

console.log(str.substring(0, 4));  // "Java"
console.log(str.substring(4, 10)); // "Script"
console.log(str.substring(4));     // "Script"(末尾まで)

// 元の文字列は変更されない
console.log(str); // "JavaScript"

indexEnd を省略すると、indexStart から文字列の末尾までを返します。

substring の特殊な挙動

substring には他のメソッドにはない独特の挙動がいくつかあります。意図しないバグを防ぐため、正確に理解しておきましょう。

引数が自動的に入れ替わる(start > end)

indexStartindexEnd より大きい場合、substring は自動的に 2 つの引数を入れ替えて実行します。

JavaScript
const str = "JavaScript";

// substring(4, 0) → 自動的に substring(0, 4) になる
console.log(str.substring(4, 0)); // "Java"
console.log(str.substring(0, 4)); // "Java"(同じ結果)

負の値は 0 に変換される

substring に負の数を渡すと、0 として扱われます。末尾からのインデックスとしては解釈されません。

JavaScript
const str = "JavaScript";

// substring(-3) → substring(0) と同じ
console.log(str.substring(-3));    // "JavaScript"(全体)

// substring(-3, 4) → substring(0, 4) と同じ
console.log(str.substring(-3, 4)); // "Java"

NaN は 0、範囲外は文字列長に丸められる

JavaScript
const str = "Hello";

// NaN → 0 として扱われる
console.log(str.substring(NaN, 3)); // "Hel"(= substring(0, 3))

// 範囲外 → 文字列の長さに丸められる
console.log(str.substring(2, 100)); // "llo"(= substring(2, 5))

// 同じインデックス → 空文字
console.log(str.substring(3, 3));   // ""
引数の状態 動作
indexStart > indexEnd 自動的に入れ替え
負の値 0 に変換
NaN 0 に変換
文字列長を超える値 文字列の長さに丸められる
indexStart === indexEnd 空文字 "" を返す
引数の自動入れ替えは便利に見えますが、変数の値が予想と違ったときにエラーではなく黙って別の結果を返すため、デバッグが困難になることがあります。意図した動作か常に確認しましょう。

substring と slice の違い

文字列の切り出しには substringslice の 2 つのメソッドがあります。機能は似ていますが、負の値の扱いstart > end の挙動が異なります。

比較項目 substring slice
負のインデックス 0 に変換される 末尾からの位置として扱う
start > end 自動的に入れ替え 空文字 "" を返す
配列 使えない(文字列専用) 使える(配列にも対応)
挙動の予測しやすさ やや難(暗黙の変換が多い) 直感的
同じ結果になる例
const str = "JavaScript";

// 正のインデックスで start < end なら同じ結果
console.log(str.substring(0, 4)); // "Java"
console.log(str.slice(0, 4));     // "Java"
結果が異なる例
const str = "JavaScript";

// 負のインデックス
console.log(str.substring(-6)); // "JavaScript"(-6 → 0)
console.log(str.slice(-6));     // "Script"(末尾から6文字)

// start > end
console.log(str.substring(4, 0)); // "Java"(自動入れ替え)
console.log(str.slice(4, 0));     // ""(空文字)
新しいコードでは slice を使う方が推奨です。負のインデックスが使えて挙動が直感的です。substring は既存コードのメンテナンスや、引数の大小関係が不確定な場面(自動入れ替えが便利な場合)で使う選択肢として残ります。

非推奨の substr との比較

substr は第 2 引数が「文字数」である点が substring / slice と異なります。しかし ECMAScript の Annex B(レガシー互換)に分類されており、新しいコードでの使用は非推奨です。

メソッド 第1引数 第2引数 状態
substring(start, end) 開始位置 終了位置(含まない) 標準
slice(start, end) 開始位置 終了位置(含まない) 標準・推奨
substr(start, length) 開始位置 文字数 非推奨
3つのメソッドの比較
const str = "JavaScript";

// インデックス4から3文字を取得したい場合
console.log(str.substring(4, 7)); // "Scr"(4〜6)
console.log(str.slice(4, 7));     // "Scr"(4〜6)
console.log(str.substr(4, 3));    // "Scr"(4から3文字)← 非推奨
substr は将来のブラウザで削除される可能性があります。既存コードで見かけた場合は slice に置き換えましょう。str.substr(start, length)str.slice(start, start + length) で同等です。

indexOf / lastIndexOf との組み合わせ

substring(や slice)は固定のインデックスだけでなく、indexOf で動的に求めた位置と組み合わせて使うのが実務の定番パターンです。

特定の文字より前・後を取得する

JavaScript
const email = "user@example.com";

// @ より前(ユーザー名)
const user = email.substring(0, email.indexOf("@"));
console.log(user); // "user"

// @ より後(ドメイン)
const domain = email.substring(email.indexOf("@") + 1);
console.log(domain); // "example.com"

ファイルパスから拡張子・ファイル名を取得する

JavaScript
const path = "/images/photo-2026.jpg";

// 拡張子を取得(最後の . 以降)
const ext = path.substring(path.lastIndexOf("."));
console.log(ext); // ".jpg"

// ファイル名を取得(最後の / 以降、拡張子なし)
const start = path.lastIndexOf("/") + 1;
const end = path.lastIndexOf(".");
const filename = path.substring(start, end);
console.log(filename); // "photo-2026"

URL からドメインを抽出する

JavaScript
const url = "https://www.example.com/path/to/page";

// プロトコル以降からパス手前まで
const afterProtocol = url.substring(url.indexOf("//") + 2);
const slashPos = afterProtocol.indexOf("/");
const domain = slashPos === -1
  ? afterProtocol
  : afterProtocol.substring(0, slashPos);

console.log(domain); // "www.example.com"
URL の解析には new URL(url) オブジェクトを使う方が確実です(url.hostname でドメインを取得可能)。substring + indexOf パターンは、URL 以外の汎用的な文字列解析に活用できます。

実務でよく使うパターン

文字数制限付きの省略表示

JavaScript
function truncate(str, max) {
  if (str.length <= max) return str;
  return str.substring(0, max) + "...";
}

console.log(truncate("JavaScriptのsubstringメソッド解説", 12));
// "JavaScriptのs..."

文字列の一部をマスキングする

JavaScript
function maskEmail(email) {
  const atPos = email.indexOf("@");
  if (atPos <= 1) return email; // 短すぎる場合はそのまま

  const visible = email.substring(0, 1); // 先頭1文字
  const domain = email.substring(atPos);  // @以降
  const masked = "*".repeat(atPos - 1);   // 残りをマスク

  return visible + masked + domain;
}

console.log(maskEmail("tanaka@example.com"));
// "t*****@example.com"

電話番号のフォーマット

JavaScript
function formatPhone(num) {
  // ハイフンなしの11桁 → 3-4-4 にフォーマット
  const digits = num.replace(/\D/g, "");
  if (digits.length !== 11) return num;

  return digits.substring(0, 3) + "-"
       + digits.substring(3, 7) + "-"
       + digits.substring(7);
}

console.log(formatPhone("09012345678"));
// "090-1234-5678"

特定の区切り文字で囲まれた文字列を取得する

JavaScript
function extractBetween(str, startDelim, endDelim) {
  const startPos = str.indexOf(startDelim);
  if (startPos === -1) return "";

  const contentStart = startPos + startDelim.length;
  const endPos = str.indexOf(endDelim, contentStart);
  if (endPos === -1) return "";

  return str.substring(contentStart, endPos);
}

console.log(extractBetween("Hello [World] !", "[", "]"));
// "World"

関連記事

よくある質問

Qsubstring と slice はどちらを使うべきですか?
A新しいコードでは slice を推奨します。負のインデックスで末尾から切り出せる点、start > end で空文字を返す直感的な挙動の点で優れています。substring は引数の自動入れ替えが便利な場面か、既存コードの保守で使うのが現実的です。
Qsubstr と substring の違いは何ですか?
Asubstring(start, end) の第2引数は終了位置、substr(start, length) の第2引数は文字数です。substr は ECMAScript の Annex B(レガシー互換)に分類されており、新しいコードでの使用は非推奨です。str.substr(s, n)str.slice(s, s + n) で置き換えられます。
Qsubstring に負の値を渡すとどうなりますか?
A負の値は 0 に変換されます。末尾からの切り出しにはなりません。末尾からの切り出しが必要な場合は slice を使ってください。str.slice(-3) で末尾 3 文字を取得できます。
QindexOf が -1 を返した場合、substring はどうなりますか?
AindexOf が -1 を返した場合、そのまま substring に渡すと -1 が 0 に変換されるため、意図しない結果になります。必ず if (pos === -1) return; のようにチェックしてから substring に渡しましょう。
Q絵文字を含む文字列で substring すると文字化けします。
A絵文字(サロゲートペア)は内部的に 2 つの char で構成されるため、substring で途中で切れることがあります。[...str].slice(0, n).join("") のように、スプレッド構文で文字単位の配列に変換してから処理すると正しく切り出せます。

まとめ

substring は文字列の一部を切り出すための標準メソッドです。

  • 基本: substring(start, end) で start を含み end を含まない範囲を返す
  • 特殊挙動: 負の値は 0 に変換、start > end は自動入れ替え
  • slice との違い: slice は負のインデックス対応、自動入れ替えなし
  • substr は非推奨: slice(start, start + length) で代替

新規コードでは slice の使用が推奨されますが、substring は引数の自動入れ替えが便利な場面や、既存コードの保守で引き続き使われています。indexOf / lastIndexOf と組み合わせた動的な文字列解析のパターンは、どちらのメソッドでも共通して活用できる重要なテクニックです。