3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

replaceAllで $& が消えた? 文字列をそのまま置換する書き方との違いを実測

3
Posted at

テンプレートの差し込み欄を、ユーザーが入力した文字列に置き換える。正規表現を使わず replaceAll の検索語を文字列にしたから、置換する側もそのまま入ると思っていませんか。

検索語が文字列でも、置換文字列の $& や $$ には意味があります。今回はNode.js v24.14.1で、置換する値にドル記号が含まれる場合を確認しました(2026-10-19)。

Before:入力した文字列の一部が、差し込み欄へ戻る

const template = "名前:{{name}}";
const input = "前$&後";
console.log(template.replaceAll("{{name}}", input));
// 名前:前{{name}}後

欲しかったのは 名前:前$&後 です。しかし、$& の部分が検索に一致した {{name}} に変わりました。replaceAll が置換を忘れたわけではありません。

この例で特別に解釈されたのは、検索する {{name}} ではなく、2つ目の引数に入れた置換文字列のほうです。

検索語が文字列の場合も、置換文字列の $$ はドル記号1つ、$& は一致した文字列を表します。置換したい値が利用者の自由入力なら、その記号を意図していないかもしれません。

After:関数から文字列を返すと、そのまま入る

const template = "名前:{{name}}";
const input = "前$&後";
console.log(template.replaceAll("{{name}}", () => input));
// 名前:前$&後

2つ目の引数を関数にし、その戻り値としてinputを渡しました。この戻り値では、置換文字列用の $& などが再解釈されません。

「一致した内容を組み合わせて置換したい」と「入力された文字列をそのまま入れたい」を、書き方で分けられます。

同じ入力で、文字列版と関数版を比べる

for (const replacement of ["$&", "$$", "$1", "前$&後"]) {
  console.log({
    replacement,
    string: "A-X-B-X".replaceAll("X", replacement),
    callback: "A-X-B-X".replaceAll("X", () => replacement),
  });
}

Node.jsで出た結果です。

置換する値 文字列を渡す 関数から返す
$& A-X-B-X A-$&-B-$&
$$ A-$-B-$ A-$$-B-$$
$1 A-$1-B-$1 A-$1-B-$1
前$&後 A-前X後-B-前X後 A-前$&後-B-前$&後

検索語を文字列の "X" としているこの例では、キャプチャがないため $1 はそのまま残りました。「ドル記号があると、どんな文字列でも壊れる」という話ではありません。

また、$& の行では元の文字列と同じ結果になります。見た目だけでは「置換が走っていない」と見誤りやすいところです。比較するテストデータには、ドル記号のない普通の名前だけでなく、実際に記号を含めた値も入れておきます。

replaceをreplaceAllへ変えるだけでは、この差は直らない

console.log("X-X".replace("X", "$&")); // X-X
console.log("X-X".replaceAll("X", "$&")); // X-X
console.log("X-X".replaceAll("X", () => "$&")); // $&-$&

1つ目のreplaceは先頭だけを置換していますが、結果は同じXです。2つ目は全て置換しても、やはり同じX。3つ目で初めて、今回欲しい「文字そのもの」が入ります。

置換の回数と、置換文字列の解釈は別の問題です。正規表現のgフラグやreplaceAllへの非global正規表現の渡し方は、以前の記事で扱いました。今回は正規表現を使わず、2つ目の引数に絞っています。

なお、関数版に変えてもHTMLとして安全になるわけではありません。置換結果をHTMLとして描画するかどうか、必要なエスケープをどこで行うかは別に確認します。

AIが生成したテンプレート処理を読むときも、2つ目の引数が「置換用の書式」なのか「文字をそのまま渡す値」なのかを見ておくと、変更の目的を説明できます。

参考: MDNのreplaceAll


未経験者向けの講座を運営しています

未経験から Next.js + Supabase + Claude Code で Webアプリを公開するまで を、全24セッションで体系化した教材です。

※ 中上級者には易しすぎる内容なので、初心者の知り合いへの紹介や社内研修の参考としてどうぞ。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?