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)
indexStart が indexEnd より大きい場合、substring は自動的に 2 つの引数を入れ替えて実行します。
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 として扱われます。末尾からのインデックスとしては解釈されません。
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、範囲外は文字列長に丸められる
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 の違い
文字列の切り出しには substring と slice の 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) |
開始位置 | 文字数 | 非推奨 |
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 で動的に求めた位置と組み合わせて使うのが実務の定番パターンです。
特定の文字より前・後を取得する
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"
ファイルパスから拡張子・ファイル名を取得する
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 からドメインを抽出する
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"
new URL(url) オブジェクトを使う方が確実です(url.hostname でドメインを取得可能)。substring + indexOf パターンは、URL 以外の汎用的な文字列解析に活用できます。実務でよく使うパターン
文字数制限付きの省略表示
function truncate(str, max) {
if (str.length <= max) return str;
return str.substring(0, max) + "...";
}
console.log(truncate("JavaScriptのsubstringメソッド解説", 12));
// "JavaScriptのs..."
文字列の一部をマスキングする
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"
電話番号のフォーマット
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"
特定の区切り文字で囲まれた文字列を取得する
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"
関連記事
- slice の使い方 — 配列・文字列の切り出し・負のインデックス対応
- indexOf で文字列の位置を取得する方法
- replace で文字列を置換する方法 — replaceAll・正規表現
- split で文字列を分割する方法
- includes で文字列の存在を判定する方法
- 文字列を結合する方法 — テンプレートリテラル・concat・join
よくある質問
slice を推奨します。負のインデックスで末尾から切り出せる点、start > end で空文字を返す直感的な挙動の点で優れています。substring は引数の自動入れ替えが便利な場面か、既存コードの保守で使うのが現実的です。substring(start, end) の第2引数は終了位置、substr(start, length) の第2引数は文字数です。substr は ECMAScript の Annex B(レガシー互換)に分類されており、新しいコードでの使用は非推奨です。str.substr(s, n) は str.slice(s, s + n) で置き換えられます。0 に変換されます。末尾からの切り出しにはなりません。末尾からの切り出しが必要な場合は slice を使ってください。str.slice(-3) で末尾 3 文字を取得できます。-1 を返した場合、そのまま substring に渡すと -1 が 0 に変換されるため、意図しない結果になります。必ず if (pos === -1) return; のようにチェックしてから 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 と組み合わせた動的な文字列解析のパターンは、どちらのメソッドでも共通して活用できる重要なテクニックです。

