置換とキャプチャ

このレッスンで分かること

  • replacereplaceAll の違いと、g フラグとの関係
  • 丸かっこのキャプチャグループと、置換文字列の中で使う $1 $2
  • 置換文字列では書けない加工を、置換関数で書く方法

置換とキャプチャ とは

当たった部分を書き換える操作です。丸かっこで囲んだ部分を取り出して並べ替えたり、関数で加工したりできます。

探すから、書き換えるへ

ここまでは「当たるか」「当たった文字は何か」を見てきました。最後は書き換えです。学習ログに 2026-04-01 と書いた日付を、表示するときだけ 2026年4月1日 に直したい、といった場面で使います。

一番単純な形は文字列同士の置き換えです。

const text = "作品は5件です"; console.log(text.replace("件", "作品")); // 作品は5作品です

replace は元の文字列を変えません。新しい文字列を返すだけです。戻り値を受け取り忘れると何も起きていないように見えます。

第 1 引数に正規表現を渡すと、形で探して書き換えられます。ただし g を付けないと最初の 1 件しか置き換わりません。

const log = "2026-04-01 と 2026-12-25 に公開"; console.log(log.replace(/\d{4}-\d{2}-\d{2}/, "[日付]")); // [日付] と 2026-12-25 に公開 console.log(log.replace(/\d{4}-\d{2}-\d{2}/g, "[日付]")); // [日付] と [日付] に公開

replaceAll を使えば g を書かずに全部を置き換えられます。次の表のとおり使い分けます。

書き方置き換える件数備考
replace(文字列, ...)最初の 1 件
replaceAll(文字列, ...)すべて
replace(正規表現, ...)g があればすべて。無ければ 1 件
replaceAll(正規表現, ...)すべてg の無い正規表現を渡すとエラーになる

最後の行が意外な点です。replaceAll に正規表現を渡すときは g が必須で、無いと TypeError で落ちます。

丸かっこで部分を取り出す

正規表現の中の丸かっこをキャプチャグループと呼びます。囲んだ部分は「当たった中身」として番号付きで取り出せて、置換文字列の中では $1 $2 の形で参照します。番号は左の丸かっこから数えて 1 始まりです。

const log = "2026-04-01 に公開"; console.log(log.replace(/(\d{4})-(\d{2})-(\d{2})/, "$1年$2月$3日")); // 2026年04月01日 に公開

順番を入れ替えることもできます。

console.log("山田 太郎".replace(/(\S+)\s+(\S+)/, "$2 $1")); // 太郎 山田

$ を使った特別な書き方は次のとおりです。

書き方意味
$1 $21 番目、2 番目のキャプチャグループ
$&当たった全体
$$ドル記号そのもの

$1 が使えるのは置換文字列の中だけです。テンプレートリテラルの ${...} とは別物なので、混ぜて書くと動きません。バッククォートで囲んでも $1$1 のまま扱われます。

置換関数で加工する

$1 は取り出した文字をそのまま差し込むだけです。加工はできません。先ほどの例で 04月 01日 と 0 が残ってしまったのは、そのためです。

加工したいときは、第 2 引数に文字列ではなく関数を渡します。当たるたびに呼ばれ、その戻り値が置き換え後の文字列になります。

const log = "2026-04-01 に公開"; const formatted = log.replace(/(\d{4})-(\d{2})-(\d{2})/g, (match, year, month, day) => { return year + "年" + Number(month) + "月" + Number(day) + "日"; }); console.log(formatted); // 2026年4月1日 に公開

引数の並びは決まっています。

引数中身
第 1 引数当たった全体。$& と同じもの
第 2 引数以降キャプチャグループが左から順に

Number("04")4 になるので、これで先頭の 0 が落ちます。文字列の置換では書けなかった加工が、関数なら普通の JavaScript として書けるわけです。

置換関数は当たった件数だけ呼ばれます。g を付けて 3 か所に当たれば 3 回呼ばれ、それぞれの戻り値がその場所に入ります。ループを自分で書く必要はありません。

キャプチャが要らないときは、第 1 引数だけ受け取れば足ります。

console.log("html css js".replace(/\w+/g, (match) => match.toUpperCase())); // HTML CSS JS

置換関数が効く場面

置換関数は、当たった文字を見てから何を返すか決められる点が強みです。表を引く形にすると、分岐を書かずに済みます。

const escapeMap = { "&": "&amp;", "<": "&lt;", ">": "&gt;" }; function escapeHtml(text) { return text.replace(/[&<>]/g, (ch) => escapeMap[ch]); } console.log(escapeHtml("5 < 10 & 20 > 10")); // 5 &lt; 10 &amp; 20 &gt; 10

入門で innerHTML に文字を流し込むと、利用者の入力に含まれた < がタグとして解釈されてしまう話が出ました。上のような関数を通しておけば、文字として表示されます。当たった 1 文字をそのまま表のキーに使えるのが、置換関数の書き味です。

置換関数の中で return を書き忘れると、戻り値が undefined になり、当たった箇所が文字列の "undefined" に置き換わります。エラーにならず、画面に undefined が並ぶ形で表に出ます。

課題の考え方

学習ログの本文にある YYYY-MM-DD 形式の日付を、すべて YYYY年M月D日 に直します。月と日の先頭の 0 は落とします。手順は 3 つです。

  1. /(\d{4})-(\d{2})-(\d{2})/g で、年と月と日をそれぞれ丸かっこで囲む
  2. 第 2 引数に関数を渡し、(match, year, month, day) を受け取る
  3. 月と日は Number に通してから連結する

日付が 1 つも無ければ、replace は元の文字列をそのまま返します。分岐を書く必要はありません。

よくある間違い

戻り値を受け取らない

replace は元の文字列を書き換えません。呼びっぱなしにすると何も変わりません。

// NG 呼んだだけで捨てている function formatLogDates(text) { text.replace(/(\d{4})-(\d{2})-(\d{2})/g, "$1年$2月$3日"); return text; } // OK 戻り値を返す function formatLogDates(text) { return text.replace(/(\d{4})-(\d{2})-(\d{2})/g, "$1年$2月$3日"); }

g を付け忘れて 1 件だけ置き換わる

テストケースが 1 件しか日付を含まないと気付けません。複数入った文字列で必ず確かめます。

const log = "2026-04-01 と 2026-12-25"; console.log(log.replace(/\d{4}-\d{2}-\d{2}/, "[日付]")); // [日付] と 2026-12-25 console.log(log.replace(/\d{4}-\d{2}-\d{2}/g, "[日付]")); // [日付] と [日付]

置換関数の第 1 引数をキャプチャだと思う

第 1 引数は当たった全体で、キャプチャは第 2 引数からです。ここを 1 つずらすと、年のつもりで 2026-04-01 全体を受け取ってしまいます。

// NG year に "2026-04-01" が入る log.replace(/(\d{4})-(\d{2})-(\d{2})/g, (year, month, day) => year); // OK 先頭で全体を受け取る log.replace(/(\d{4})-(\d{2})-(\d{2})/g, (match, year, month, day) => year);

要件

  1. 関数名は formatLogDates、引数は文字列の text を 1 つ受け取る
  2. 4 桁の数字とハイフンで区切られた 2 桁の数字 2 つ、という形をすべて置き換える
  3. 月と日の先頭の 0 は落とす。04 は 4、01 は 1 にする
  4. 戻り値は置き換え後の文字列。日付が無ければ元の文字列をそのまま返す

入出力例

formatLogDates("2026-04-01 プロフィールサイトを公開")"2026年4月1日 プロフィールサイトを公開" formatLogDates("2026-04-01 と 2026-12-25 に公開")"2026年4月1日 と 2026年12月25日 に公開" formatLogDates("日付なしのメモ")"日付なしのメモ" formatLogDates("")"" formatLogDates("2026-4-1 は形が違う")"2026-4-1 は形が違う"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.js
main.js
学習モード

メモ

置換とキャプチャ

⌘S で保存