【JavaScript】文字列から開始位置と文字数を指定して取得する方法|slice・substring・substrの違いと負のインデックス・実用例まで解説

JavaScriptで「文字列の3文字目から3文字分だけ取り出したい」のように、開始位置と文字数を指定して部分文字列を取得したい場面はよくあります。郵便番号や日付の固定長データを切り出したり、カード番号の下4桁以外を伏せ字にしたりするケースです。

使えるメソッドは slice() / substring() / substr() の3つですが、それぞれ引数の意味が微妙に異なり、substr() は非推奨です。この記事では正しい書き方と使い分け、そして絵文字で文字化けする落とし穴まで実コードで解説します。

この記事の結論:「開始位置+文字数」で取り出すなら slice(開始, 開始 + 文字数) が基本です。substr(開始, 文字数) は文字数を直接渡せて直感的ですが非推奨なので、新しいコードでは使わないようにしましょう。
スポンサーリンク

slice() で取得する(推奨)

slice(開始, 終了) は開始位置から終了位置の手前までを取り出します。「文字数」で取り出したいときは、終了位置に 開始 + 文字数 を渡すのがポイントです。

slice() で文字数を指定して取得
const str = "abcdefg";
const start = 2;  // 開始位置(0始まり)
const length = 3; // 取り出す文字数

const result = str.slice(start, start + length);
console.log(result); // "cde"
slice() は文字列だけでなく配列にも使えます。基本的な挙動はsliceメソッドで配列や文字列の一部を切り取る方法で解説しています。

終了位置を省略すると末尾まで取得

第2引数を省略すると、開始位置から文字列の末尾までを取り出します。

末尾まで取得
const str = "abcdefg";
console.log(str.slice(2)); // "cdefg"(2文字目から最後まで)

負のインデックスで末尾から数える

slice() は負の値を「末尾からの位置」として扱えます。「末尾の3文字」を取り出すといった用途に便利です。

負のインデックス
const str = "abcdefg";
console.log(str.slice(-3));    // "efg"(末尾から3文字)
console.log(str.slice(-3, -1)); // "ef"(末尾から3文字目〜末尾の手前まで)
console.log(str.slice(1, -1));  // "bcdef"(先頭と末尾を1文字ずつ除く)

substring() で取得する

substring(開始, 終了) も基本は slice() と同じで、文字数で取り出すなら終了位置に 開始 + 文字数 を渡します。substringメソッドの詳細もあわせて参照してください。

substring() で文字数を指定して取得
const str = "abcdefg";
const start = 2;
const length = 3;

const result = str.substring(start, start + length);
console.log(result); // "cde"
slice() との違いに注意:substring()負の値を 0 として扱い、さらに開始 > 終了のときは引数を自動で入れ替えます。末尾から数えたい場合や、計算結果が負になりうる場合は slice() の方が安全です。
substring() の独特な挙動
const str = "abcdefg";

console.log(str.substring(-3));   // "abcdefg"(負の値は 0 扱い → 全体)
console.log(str.substring(5, 2)); // "cde"(5と2が入れ替わる → substring(2, 5))
console.log(str.slice(5, 2));     // ""(slice は入れ替えないので空文字)

substr() は非推奨(開始位置+文字数の旧定番)

substr(開始, 文字数) は第2引数にそのまま文字数を渡せるため、「開始位置+文字数」の用途には一番直感的でした。ただし現在は非推奨(deprecated)です。仕様上は互換性維持のための「Annex B(レガシー機能)」として残されているため、すぐに使えなくなるわけではありませんが、新規コードでは避けるのが推奨です。

substr()(非推奨)
const str = "abcdefg";

// substr(開始, 文字数) → 文字数をそのまま渡せる
console.log(str.substr(2, 3)); // "cde"

// 置き換え:slice(開始, 開始 + 文字数)
console.log(str.slice(2, 2 + 3)); // "cde"(同じ結果)
移行のコツ:substr(start, length)slice(start, start + length) に置き換えれば同じ結果になります。既存コードで substr() を見かけたら、この形に書き換えておくと安心です。

slice / substring / substr の違い

メソッド 第2引数の意味 負の値 推奨度
slice(開始, 終了) 終了位置(含まない) 末尾からの位置として有効 ◎ 推奨
substring(開始, 終了) 終了位置(含まない) 0 として扱う・引数を入替 ○ 可
substr(開始, 文字数) 文字数 開始のみ末尾から可 × 非推奨
迷ったら slice() を使えば間違いありません。負のインデックスに対応し、引数の入れ替えのような意外な挙動もないため、もっとも扱いやすいメソッドです。

開始位置を動的に決める(indexOf 連携)

開始位置を固定値ではなく「特定の文字の次から」にしたいときは、indexOf() で位置を検索して slice() に渡します。

区切り文字の後ろを取り出す
const line = "name: 田中太郎";

const start = line.indexOf(":") + 1; // ":" の次の位置
const value = line.slice(start).trim();
console.log(value); // "田中太郎"
「特定の文字より後ろをまるごと削除したい」場合は指定した文字以降の文字列を削除する方法、区切り文字で分けたいだけならsplit() で文字列を配列に変換する方法も便利です。

【注意】絵文字・サロゲートペアで文字化けする問題

slice() などは内部的にUTF-16のコード単位で文字を数えます。そのため絵文字(😀 など)や一部の漢字(𠮷 など)のように2つのコード単位で1文字を表す「サロゲートペア」を途中で切ると、文字化け(壊れた半端な文字)が発生します。

下のコードでは絵文字を \u{1F600} というコードポイントエスケープで表記しています(記事中に絵文字をそのまま埋め込むと環境によって化けるため)。実際の文字列は「絵文字+abc」です。

NG: 絵文字が壊れる
const str = "\u{1F600}abc"; // 絵文字 + "abc"

console.log(str.length);      // 5(絵文字が 2 コード単位とカウントされる)
console.log(str.slice(0, 1)); // 壊れた半端な文字(文字化けする)

コードポイント(見た目の1文字)単位で扱いたいときは、スプレッド構文や Array.from() でいったん配列に分割してから取り出します。

OK: コードポイント単位で取得
function subByCodePoint(str, start, length) {
  return [...str].slice(start, start + length).join("");
}

const str = "\u{1F600}abc"; // 絵文字 + "abc"
console.log([...str].length);           // 4(絵文字が 1 文字としてカウント)
console.log(subByCodePoint(str, 0, 1)); // 絵文字1文字(壊れない)
console.log(subByCodePoint(str, 1, 2)); // "ab"

よくある実用例

固定長データを切り出す

日付や郵便番号のように桁位置が決まっているデータは、開始位置と文字数で機械的に分解できます。

YYYYMMDD を分解
const ymd = "20260614";

const year  = ymd.slice(0, 4); // "2026"
const month = ymd.slice(4, 6); // "06"
const day   = ymd.slice(6, 8); // "14"

console.log(`${year}年${month}月${day}日`); // "2026年06月14日"

文字列をマスキングする(伏せ字)

カード番号の下4桁だけ残して伏せ字にする、といった処理も slice() で簡潔に書けます。

下4桁以外を伏せ字に
const card = "1234567812345678";

const masked = "*".repeat(card.length - 4) + card.slice(-4);
console.log(masked); // "************5678"

先頭・末尾から指定文字数だけ取得

「先頭からN文字」「末尾からN文字」だけが欲しいケースは下記の記事で個別に解説しています。

よくある質問(FAQ)

Qsubstring() と substr() の違いは何ですか?
A第2引数の意味が違います。substring(start, end) の第2引数は終了インデックス(その位置は含まない)ですが、substr(start, length) の第2引数は取り出す文字数です。substr() は非推奨なので、新しいコードでは slice()substring() を使ってください。
Q開始位置と文字数で取り出すベストな方法は?
Aslice(開始, 開始 + 文字数) が推奨です。負のインデックスに対応していて汎用性が高く、substring() のように引数が勝手に入れ替わることもありません。substr() は文字数を直接渡せて便利でしたが非推奨です。
Qインデックスは0と1のどちらから始まりますか?
A0から始まります。つまり先頭の文字が0番目、2番目の文字はインデックス1です。「3文字目から」取り出したい場合は開始位置に 2 を指定します。
Q絵文字を含む文字列を正しく切り出すには?
Aslice() はUTF-16のコード単位で数えるため、絵文字(サロゲートペア)を途中で切ると文字化けします。[...str]Array.from(str) でコードポイント単位の配列に変換してから slice() すると、見た目の1文字を崩さずに取り出せます。

まとめ

JavaScriptで開始位置と文字数を指定して文字列を取得する方法のポイントを整理します。

  • 「開始位置+文字数」は slice(開始, 開始 + 文字数) が基本
  • slice() は負のインデックス対応・引数入れ替えなしで一番扱いやすい
  • substring() は負の値を0扱い・開始>終了で引数を入れ替える点に注意
  • substr(開始, 文字数) は非推奨。slice(開始, 開始 + 文字数) に置き換える
  • 絵文字を含む文字列は [...str] でコードポイント単位にしてから切り出す

関連する文字列操作として、指定した文字以降を削除する方法substringメソッドの使い方sliceメソッドの使い方もあわせて確認すると理解が深まります。