13.

JavaScript の文字列置換|replaceAll と replace の違い・正規表現

編集
この記事の要点
  • すべて置換したいなら replaceAll()replace() は文字列指定だと最初の 1 個だけ
  • 正規表現で全置換するなら /g フラグが必須。replaceAll()/g 無しの正規表現は渡せない
  • 置換後の文字列で $ は特別な意味を持つ。入力値をそのまま置換文字列にしない
  • 置換文字列の代わりに関数を渡すと、マッチごとに結果を計算できる
  • 文字列は変更できない。戻り値を受け取らないと何も起きない

基本

const s = "赤・青・赤・緑";

console.log(s.replace("赤", "黄"));      // 黄・青・赤・緑   ← 最初の 1 個だけ
console.log(s.replaceAll("赤", "黄"));   // 黄・青・黄・緑   すべて
console.log(s.replace(/赤/g, "黄"));     // 黄・青・黄・緑   正規表現 + g

console.log(s);                         // 赤・青・赤・緑   元は変わらない

// 戻り値を受け取らないと意味がない
s.replaceAll("赤", "黄");                // 何も起きない
const result = s.replaceAll("赤", "黄"); // これが必要

JavaScript の文字列は変更できない(イミュータブル)ため、置換系のメソッドは必ず新しい文字列を返します。

replaceAll と正規表現

const s = "a1b2c3";

console.log(s.replaceAll(/\d/g, "#"));   // a#b#c#
// console.log(s.replaceAll(/\d/, "#"));
// TypeError: replaceAll must be called with a global RegExp

replaceAll() に正規表現を渡すときは /g が必須です。付け忘れると例外になるため、かえって間違いに気づけます。

正規表現でよく使う置換

// 連続する空白を 1 つにまとめる
"a   b\t\tc".replace(/\s+/g, " ");            // "a b c"

// 全角スペースも含めて前後を削る
"  abc  ".replace(/^[\s ]+|[\s ]+$/g, ""); // "abc"

// 数字だけを取り除く
"a1b2".replace(/\d/g, "");                    // "ab"

// 大文字小文字を無視して置換
"Hello HELLO".replace(/hello/gi, "やあ");      // "やあ やあ"

// 改行を <br> に(改行コードの違いを吸収する)
text.replace(/\r\n|\r|\n/g, "<br>");

// 3 桁区切り(先読みを使う)
"1234567".replace(/\B(?=(\d{3})+(?!\d))/g, ",");   // "1,234,567"
// 実務では toLocaleString のほうが確実
(1234567).toLocaleString("ja-JP");                 // "1,234,567"

キャプチャした部分を使う

// $1 $2 で丸かっこの中身を参照する
"2026-09-07".replace(/(\d{4})-(\d{2})-(\d{2})/, "$1年$2月$3日");
// "2026年09月07日"

// 名前付きキャプチャなら意味が分かる
"2026-09-07".replace(
  /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/,
  "$<y>年$<m>月$<d>日",
);

// 入れ替え
"田中 太郎".replace(/(\S+) (\S+)/, "$2 $1");   // "太郎 田中"
記号意味
$1 $21 番目・2 番目のキャプチャ
$&マッチした文字列全体
$`マッチより前の部分
$'マッチより後ろの部分
$$ドル記号そのもの

置換文字列に入力値を使わない

const input = "$&$&";               // 利用者が入力した値

console.log("abc".replace("b", input));
// "a$&$&c" ではなく "abbc" になる($& がマッチ全体に置き換わる)

// 関数を渡せば特殊記号が解釈されない
console.log("abc".replace("b", () => input));   // "a$&$&c"

置換後の文字列に利用者の入力を使うときは、関数で渡す$$$ にエスケープしてください。

関数で置換する

// マッチごとに計算する
"1 2 3".replace(/\d/g, (m) => Number(m) * 2);      // "2 4 6"

// 引数は (マッチ全体, $1, $2, ..., 位置, 元の文字列)
"a1b2".replace(/([a-z])(\d)/g, (all, ch, num, index) => {
  return `${ch.toUpperCase()}${num}@${index}`;
});
// "A1@0B2@2"

// 名前付きキャプチャは最後の引数にオブジェクトで来る
"2026-09".replace(/(?<y>\d{4})-(?<m>\d{2})/, (...args) => {
  const g = args.at(-1);
  return `${g.y}/${g.m}`;
});

// 辞書で一括変換する
const map = { "<": "&lt;", ">": "&gt;", "&": "&amp;" };
const escaped = text.replace(/[<>&]/g, (c) => map[c]);

特殊文字を含む文字列で置換する

const keyword = "a.b";       // 利用者が入力した検索語

// 正規表現に直接埋めると . が「任意の 1 文字」として働いてしまう
new RegExp(keyword, "g");    // /a.b/g → "axb" にもマッチする

// 文字列指定の replaceAll なら特殊文字の心配がない(推奨)
text.replaceAll(keyword, "***");

// どうしても正規表現が必要ならエスケープする
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
new RegExp(escapeRe(keyword), "g");

利用者の入力をそのまま new RegExp() に渡さないでください。意図しないマッチに加え、複雑なパターンでは処理が止まる(ReDoS)恐れがあります。

置換以外の方法

// 分割して連結する(replaceAll が使えない古い環境向け)
"a-b-c".split("-").join("_");        // "a_b_c"

// 前後の空白を削る
"  abc  ".trim();                   // "abc"
"  abc  ".trimStart();              // "abc  "

// 部分的に切り出して組み立てる
const s = "abcdef";
s.slice(0, 2) + "X" + s.slice(3);   // "abXdef"

// 先頭・末尾だけ置換
"###abc".replace(/^#+/, "");        // "abc"

// 文字単位で変換する
"abc".split("").map((c) => c.toUpperCase()).join("");   // "ABC"

DOM の文字列を置換するとき

const el = document.querySelector("#target");

// textContent なら安全(タグとして解釈されない)
el.textContent = el.textContent.replaceAll("旧", "新");

// innerHTML への代入は危険。入力値が混ざると XSS になる
// el.innerHTML = el.innerHTML.replaceAll(userInput, "...");

// innerHTML を使わざるを得ないときはエスケープしてから
const escapeHtml = (s) =>
  s.replace(/[&<>"']/g, (c) =>
    ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);

innerHTML に対する置換は、元の HTML 構造を壊すうえに XSS の入口になります。文字を書き換えるだけなら textContent を使ってください。

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 記述方法
  2. コメント
  3. 変数の宣言
  4. 関数
  5. 演算子
  6. 条件文
  7. 配列
  8. 連想配列
  9. ループ処理
  10. 非同期処理
  11. 同期処理
  12. 確認ウィンドウを表示する方法
  13. 文字の置換
  14. base urlを取得する方法
  15. formのsubmit前にjavascriptを呼び出す方法
  16. undefinedのイコール判定
  17. Javascript のみで form を post で submit する方法

最近更新/作成されたページ