はじめに
JavaScriptの文字列操作は、すべて「文字列は不変(immutable)」「内部表現はUTF-16」という前提で動作します。この記事では、実務でよく使うStringメソッドを体系的に整理し、使いこなすためのポイントを解説します。
概要
文字列操作のメソッドは、用途別に以下のカテゴリーに分類できます。
基本メソッド
取り出し・スライス
文字列から部分文字列を取得する際は、sliceメソッドの使用を推奨します。
const s = "abcdef";
// 末尾の1文字を取得(ES2022で追加)
s.at(-1); // 'f'
// 部分文字列の取り出し
s.slice(2, 5); // 'cde' インデックス[2,5)の範囲
s.slice(3); // 'def' 開始位置のみ指定
// substring は負数に対応していないため非推奨
// substr は廃止予定のため使用を避ける
sliceとsubstringの違い
-
slice: 負数を使って末尾から数えることが可能 -
substring: 負数を0として扱い、引数の大小を自動で入れ替える
検索・判定
文字列内の特定パターンを検索する方法です。
const s = "hello world";
// 部分文字列の存在確認
s.includes("wor"); // true
s.startsWith("he"); // true
s.endsWith("ld"); // true
// 位置の取得(見つからない場合は-1を返す)
s.indexOf("o"); // 4
s.lastIndexOf("o"); // 7
置換
文字列の一部を別の文字列に置き換えます。
// 最初の一致のみ置換
"bananas".replace("na", "NA"); // 'baNAnas'
// すべての一致を置換(ES2021で追加)
"bananas".replaceAll("na", "NA"); // 'baNANAs'
// 正規表現とコールバック関数を使った高度な置換
"2025-10-25".replace(/(\d{4})-(\d{2})-(\d{2})/, (_, y, m, d) => `${m}/${d}/${y}`);
// '10/25/2025'
正規表現による検索
正規表現を使った柔軟なパターンマッチングが可能です。
const s = "a1 b22 c333";
// すべての一致を配列で取得
s.match(/\d+/g); // ['1','22','333'](一致なしの場合はnull)
// 最初の一致位置を取得
s.search(/\d+/); // 1
// すべての一致とキャプチャグループを取得(ES2020で追加)
[...s.matchAll(/([a-z])(\d+)/g)]
// [['a1','a','1'], ['b22','b','22'], ['c333','c','333']]
整形・フォーマット
前後の空白除去やパディング処理を行います。
// 前後の空白文字を削除
" hi \n".trim(); // 'hi'
// 指定文字数になるまで埋める
"7".padStart(3, "0"); // '007'
"7".padEnd(3, "0"); // '700'
大文字・小文字の変換
ロケールに依存する変換と依存しない変換があります。
// 基本的な変換
"straße".toUpperCase(); // 'STRASSE'
// ロケールを考慮した変換(トルコ語など特殊なルールに対応)
"istanbul".toLocaleUpperCase('tr');
分割と結合
文字列を配列に分割したり、配列を文字列に結合したりします。
// 文字列を配列に分割
"apples,oranges,kiwi".split(","); // ['apples','oranges','kiwi']
"2025-10-25".split("-", 2); // ['2025','10'](上限指定)
// 配列を文字列に結合
["a","b","c"].join("-"); // 'a-b-c'
反復と繰り返し
// 文字列を1文字ずつ処理
for (const ch of "cat") {
console.log(ch); // 'c', 'a', 't'
}
// 文字列を指定回数繰り返す
"abc".repeat(3); // 'abcabcabc'
Unicode・絵文字・合成文字の扱い
JavaScriptの文字列処理で特に注意が必要なのが、Unicode対応です。
文字数のカウント問題
lengthプロパティはUTF-16のコード単位を返すため、絵文字や合成文字では見た目と異なる値になります。
// UTF-16コード単位でのカウント
"👩💻".length; // 5(見た目は1文字)
// 実際の文字数をカウント
[..."👩💻"].length; // 1
Array.from("👩💻").length; // 1
正規化による一致判定
アクセント記号や濁点などは、複数の表現方法が存在する場合があります。
const a = "é"; // U+00E9(1文字の合成済み文字)
const b = "e\u0301"; // 'e' + 合成用アクセント記号
// そのままでは一致しない
a === b; // false
// 正規化すると一致する
a.normalize("NFC") === b.normalize("NFC"); // true
正規化形式
- NFC: 合成済み文字を優先
- NFD: 分解形式を優先
- NFKC/NFKD: 互換性を考慮した正規化
安全な末尾文字の取得
atメソッドを使うと、サロゲートペアを崩さずに文字を取得できます。
const s = "A🙂";
s.at(-1); // '🙂'(正しく取得)
s[s.length - 1]; // 不完全なサロゲートペア(非推奨)
文字コード関連
const s = "A🙂";
// 文字からコードポイントを取得
s.codePointAt(0); // 65
s.codePointAt(1); // 128578
// コードポイントから文字を生成
String.fromCodePoint(65); // 'A'
String.fromCodePoint(0x1F642); // '🙂'
ロケールを考慮した比較・ソート
言語によって文字の並び順が異なるため、ロケールを指定した比較が必要です。
// ドイツ語の並び順で比較
"ä".localeCompare("z", "de"); // -1(äはzより前)
// 配列のソート
["ä","z","a"].sort((a,b) => a.localeCompare(b, 'de'));
// ['a', 'ä', 'z']
実践的なパターン
テンプレートリテラルによる文字列生成
変数を埋め込んだ文字列を簡潔に記述できます。
const user = "Kato";
const msg = `Hello, ${user}!`;
大量の文字列連結
配列とjoinを使うと、パフォーマンスが向上します。
const parts = [];
for (let i = 0; i < 10000; i++) {
parts.push(String(i));
}
const result = parts.join(",");
条件付きで末尾を削除
const dropSuffix = (s, suffix) =>
s.endsWith(suffix) ? s.slice(0, -suffix.length) : s;
dropSuffix("report.csv", ".csv"); // 'report'
連続する空白を1つに集約
"foo bar \t baz".replace(/\s+/g, " ");
// 'foo bar baz'
キャメルケースからスネークケースへ変換
"camelCaseString".replace(/[A-Z]/g, m => "_" + m.toLowerCase());
// 'camel_case_string'
URLクエリの簡易パース
const q = "a=1&b=2&a=3";
Object.fromEntries(new URLSearchParams(q));
// { a: '3', b: '2' }(同名パラメータは最後の値が有効)
よくある質問
Q: sliceとsubstringはどう使い分けるべきですか?
A: 基本的にsliceを使用してください。sliceは負数で末尾からの位置指定ができ、より直感的です。substringは後方互換性のために残されているメソッドです。
Q: replaceAllが使えない環境ではどうすればよいですか?
A: 正規表現のグローバルフラグ/pattern/gとreplaceを組み合わせるか、環境の更新を検討しましょう。
// replaceAllの代替
"bananas".replace(/na/g, "NA"); // 'baNANAs'
Q: 大文字小文字を無視して検索するには?
A: すべて小文字に変換してから比較するか、正規表現のiフラグを使用します。
// 方法1: 小文字変換
s.toLowerCase().includes(term.toLowerCase())
// 方法2: 正規表現
/term/i.test(s)
まとめ
JavaScriptの文字列操作では、以下の点に注意してメソッドを選択しましょう。
- 部分文字列の取得には
sliceを使用する - Unicode文字を扱う場合は
atや[...str]でコードポイント単位で処理する - ロケールが関係する場合は
localeCompareやtoLocaleUpperCaseを使用する - 正規化が必要な場合は
normalizeメソッドを活用する
これらのメソッドを適切に使い分けることで、堅牢な文字列処理を実装できます。