JavaScriptで文字列を置換するには replace() メソッドを使います。しかし、デフォルトでは最初の1つしか置換されないという落とし穴があり、「全部置換したかったのに1つだけしか変わらない」というミスは非常に多く見られます。
この記事では、replace()の基本動作から、replaceAll()(ES2021)、正規表現による高度な置換、コールバック関数を使った動的置換、そして実務で即使えるパターン集(HTMLエスケープ、電話番号フォーマット、カンマ区切りなど)まで、文字列置換に関するすべてを体系的に解説します。
この記事で学べること
- replace()メソッドの基本構文と「最初の1つだけ置換」の仕組み
- 全置換する3つの方法(正規表現gフラグ・replaceAll・split+join)
- 正規表現フラグ(g / i / m)を活用した高度な置換パターン
- キャプチャグループ($1, $2)と後方参照による構造変換
- コールバック関数を使った動的な置換処理
- 実務で即使える置換パターン集(HTML除去・電話番号・カンマ区切り・XSS対策)
- replace()のよくあるミスと注意点
replace()メソッドの基本構文と動作
String.prototype.replace() は、文字列中の指定したパターンに一致する部分を別の文字列に置換し、新しい文字列を返すメソッドです。元の文字列は変更されません(イミュータブル)。
基本構文
// 構文
const newStr = str.replace(pattern, replacement);
// pattern: 検索する文字列 または 正規表現
// replacement: 置換する文字列 または コールバック関数
// 戻り値: 置換後の新しい文字列(元の文字列は変化しない)
もっとも基本的な使い方は、文字列を別の文字列に置き換えるパターンです。
JavaScript
const message = 'Hello, World!';
// "World" を "JavaScript" に置換
const result = message.replace('World', 'JavaScript');
console.log(result); // "Hello, JavaScript!"
console.log(message); // "Hello, World!"(元の文字列は変わらない)
実行結果
Hello, JavaScript!
Hello, World!
ポイント:replace() は元の文字列を変更せず、常に新しい文字列を返します。結果を使うには変数に代入する必要があります。
最初の一致だけ置換される仕組みと注意点
replace() で文字列パターンを指定した場合、最初に見つかった一致だけが置換され、残りはそのままです。これはJavaScript初心者がもっとも陥りやすい落とし穴の一つです。
JavaScript
const text = 'りんご と みかん と りんご と ぶどう';
// 文字列で検索すると、最初の「りんご」だけが置換される
const result = text.replace('りんご', 'バナナ');
console.log(result);
// "バナナ と みかん と りんご と ぶどう"
// → 2つ目の「りんご」はそのまま!
実行結果
バナナ と みかん と りんご と ぶどう
注意:replace() に文字列パターンを渡した場合、最初の一致のみが置換されます。すべての一致を置換したい場合は、次のセクションで解説する方法を使ってください。
この動作は仕様どおりですが、意図せず「1つだけ置換」してしまうミスが多発します。以下のようなケースで問題になります。
よくあるミスの例
// CSVデータからカンマを除去したい
const csv = '1,000,000';
// ❌ 最初のカンマしか除去されない
csv.replace(',', ''); // "1000,000"
// ❌ 2回呼んでも2つまで
csv.replace(',', '').replace(',', ''); // "1000000"(たまたま成功)
// → カンマの数が不定なら、この方法は危険
すべての一致を確実に置換する方法を次のセクションで詳しく解説します。
すべての一致を置換する3つの方法
replace() のデフォルト動作(最初の1つだけ置換)を克服し、すべての一致を置換する方法は主に3つあります。
| 方法 |
書き方 |
対応環境 |
| 正規表現 + gフラグ |
str.replace(/pattern/g, rep) |
全ブラウザ |
| replaceAll() |
str.replaceAll(search, rep) |
ES2021〜 |
| split + join |
str.split(search).join(rep) |
全ブラウザ |
方法1:正規表現 + gフラグ(もっとも汎用的)
正規表現の g(global)フラグ を付けると、文字列内のすべての一致箇所が置換されます。もっとも古くから使える方法で、あらゆる環境で動作します。
JavaScript
const text = 'りんご と みかん と りんご と ぶどう';
// 正規表現 + gフラグですべての「りんご」を置換
const result = text.replace(/りんご/g, 'バナナ');
console.log(result);
// "バナナ と みかん と バナナ と ぶどう"
実行結果
バナナ と みかん と バナナ と ぶどう
カンマ除去の例も正規表現で安全に書けます。
JavaScript
const price = '1,000,000';
// すべてのカンマを除去
const num = price.replace(/,/g, '');
console.log(num); // "1000000"
方法2:split() + join()(正規表現なしで全置換)
正規表現を使わずに全置換するテクニックとして、split() で分割してから join() で結合する方法があります。
JavaScript
const text = 'りんご と みかん と りんご と ぶどう';
// split で「りんご」を区切りとして分割 → join で「バナナ」で結合
const result = text.split('りんご').join('バナナ');
console.log(result);
// "バナナ と みかん と バナナ と ぶどう"
split + join のメリット:正規表現の特殊文字(. * + ? ( ) [ ] など)をエスケープする必要がありません。ユーザー入力をそのまま検索文字列に使える安全な方法です。
replaceAll()メソッド(ES2021〜)
ES2021で追加された replaceAll() は、名前のとおりすべての一致を置換するメソッドです。正規表現を使わずに全置換でき、コードの可読性が大幅に向上します。
基本構文
// 構文
const newStr = str.replaceAll(pattern, replacement);
// pattern に文字列を渡すと、すべての一致を置換
// pattern に正規表現を渡す場合は、gフラグ必須
JavaScript
const text = 'りんご と みかん と りんご と ぶどう';
// replaceAll() ですべての「りんご」を置換
const result = text.replaceAll('りんご', 'バナナ');
console.log(result);
// "バナナ と みかん と バナナ と ぶどう"
実行結果
バナナ と みかん と バナナ と ぶどう
replaceAll() に正規表現を渡す場合の注意
replaceAll() に正規表現を渡す場合は、必ず g フラグを付ける必要があります。g フラグがないとTypeErrorが発生します。
JavaScript
const text = 'abc123def456';
// ✅ gフラグ付き → OK
text.replaceAll(/[0-9]+/g, 'NUM'); // "abcNUMdefNUM"
// ❌ gフラグなし → TypeError!
text.replaceAll(/[0-9]+/, 'NUM');
// TypeError: String.prototype.replaceAll called with a non-global RegExp
replace() vs replaceAll() 使い分けガイド
| やりたいこと |
推奨メソッド |
理由 |
| 最初の1つだけ置換 |
replace() |
デフォルト動作で実現 |
| 単純な文字列の全置換 |
replaceAll() |
可読性が高い |
| パターンによる全置換 |
replace(/pattern/g) |
正規表現の柔軟さ |
| IE対応が必要 |
replace(/pattern/g) |
replaceAllはIE非対応 |
| ユーザー入力で全置換 |
replaceAll() or split+join |
特殊文字の心配なし |
おすすめ:ES2021以降の環境(Node.js 15+、Chrome 85+、Safari 13.1+)であれば、単純な全置換には replaceAll() を使うのがもっとも読みやすく安全です。
正規表現を活用した高度な置換パターン
replace() の真価は正規表現と組み合わせたときに発揮されます。フラグの使い分け、複数パターンの一括置換、キャプチャグループによる構造変換など、実務で役立つテクニックを紹介します。
大文字・小文字を無視して置換(iフラグ)
i(case-insensitive)フラグ を使うと、大文字・小文字を区別せずに検索・置換できます。
JavaScript
const text = 'Hello hello HELLO';
// iフラグなし:完全一致のみ
text.replace(/hello/g, 'Hi');
// "Hello Hi HELLO"(小文字の hello だけ)
// giフラグ:大文字小文字を無視してすべて置換
text.replace(/hello/gi, 'Hi');
// "Hi Hi Hi"
実行結果
Hello Hi HELLO
Hi Hi Hi
複数パターンの一括置換(| 演算子)
正規表現の |(OR演算子) を使うと、複数のパターンを1回のreplace()で同時に置換できます。
JavaScript
const text = '犬と猫とうさぎがいます';
// 「犬」「猫」「うさぎ」をすべて「動物」に置換
const result = text.replace(/犬|猫|うさぎ/g, '動物');
console.log(result);
// "動物と動物と動物がいます"
パターンごとに異なる文字列に置換したい場合は、コールバック関数(後述)を使います。
JavaScript
const text = '犬と猫とうさぎがいます';
// パターンごとに異なる置換先を指定
const map = { '犬': 'dog', '猫': 'cat', 'うさぎ': 'rabbit' };
const result = text.replace(/犬|猫|うさぎ/g, (match) => map[match]);
console.log(result);
// "dogとcatとrabbitがいます"
キャプチャグループと参照による構造変換
正規表現のキャプチャグループ () で捕捉した部分を、置換文字列中で $1, $2, $3… として参照できます。文字列の構造を変換するときに非常に便利です。
JavaScript
// 例1: 日付フォーマットの変換(YYYY/MM/DD → YYYY年MM月DD日)
const date = '2025/03/15';
const jpDate = date.replace(
/(d{4})/(d{2})/(d{2})/,
'$1年$2月$3日'
);
console.log(jpDate); // "2025年03月15日"
JavaScript
// 例2: 姓名の入れ替え("姓 名" → "名 姓")
const name = 'Tanaka Taro';
const swapped = name.replace(/(w+)s(w+)/, '$2 $1');
console.log(swapped); // "Taro Tanaka"
JavaScript
// 例3: HTMLタグを変換(em → strong)
const html = '<em>重要</em>なお知らせ';
const result = html.replace(
/<em>(.+?)</em>/g,
'<strong>$1</strong>'
);
console.log(result);
// "<strong>重要</strong>なお知らせ"
置換文字列で使える特殊パターン
replace() の置換文字列では、$1 以外にもいくつかの特殊パターンが使えます。
| パターン |
意味 |
用途 |
$1, $2, ... |
キャプチャグループの一致 |
構造変換 |
$& |
一致した文字列全体 |
一致をラップ |
$` |
一致の前の部分 |
前方コンテキスト |
$' |
一致の後の部分 |
後方コンテキスト |
$$ |
リテラルの $ 文字 |
$ を挿入 |
JavaScript
// $& の活用:一致した部分をカッコで囲む
const text = 'JavaScript is great';
const result = text.replace(/w+/g, '【$&】');
console.log(result);
// "【JavaScript】 【is】 【great】"
コールバック関数を使った動的な置換
replace() の第2引数には文字列だけでなく関数(コールバック)を渡すことができます。一致するたびに関数が呼ばれ、その戻り値が置換文字列になります。条件分岐や計算を含む高度な置換が可能です。
コールバック関数の構文
str.replace(pattern, function(match, p1, p2, ..., offset, string) {
// match: 一致した文字列全体
// p1, p2: キャプチャグループ(あれば)
// offset: 一致した位置(インデックス)
// string: 元の文字列全体
return replacementString;
});
例1:一致した数値を2倍にする
JavaScript
const text = 'りんご3個、みかん5個、ぶどう2個';
// 数値を見つけるたびに2倍にする
const result = text.replace(/d+/g, (match) => {
return Number(match) * 2;
});
console.log(result);
// "りんご6個、みかん10個、ぶどう4個"
例2:英単語の先頭を大文字にする(タイトルケース変換)
JavaScript
const title = 'hello world from javascript';
const titleCase = title.replace(/w/g, (char) => {
return char.toUpperCase();
});
console.log(titleCase);
// "Hello World From Javascript"
例3:テンプレート文字列の変数展開
JavaScript
const template = '{{name}}さん、{{item}}を{{count}}個注文しました';
const data = {
name: '田中',
item: 'コーヒー',
count: '3'
};
const result = template.replace(
/{{(w+)}}/g,
(match, key) => data[key] || match
);
console.log(result);
// "田中さん、コーヒーを3個注文しました"
コールバック関数のメリット:静的な置換文字列では実現できない、条件分岐・計算・外部データ参照を含む柔軟な置換が可能です。実務ではテンプレートエンジンやサニタイズ処理でよく使われます。
例4:キャプチャグループとコールバックの組み合わせ
JavaScript
// CSSのrgb値を16進カラーコードに変換
const css = 'color: rgb(255, 128, 0); background: rgb(0, 0, 255);';
const result = css.replace(
/rgb((d+),s*(d+),s*(d+))/g,
(match, r, g, b) => {
const hex = [r, g, b]
.map(n => Number(n).toString(16).padStart(2, '0'))
.join('');
return '#' + hex;
}
);
console.log(result);
// "color: #ff8000; background: #0000ff;"
実務でよく使う置換パターン集
ここからは、実際の開発現場ですぐにコピペして使える置換パターンを厳選して紹介します。
HTMLタグの除去(プレーンテキスト化)
HTMLタグを取り除いて純粋なテキストだけを取得したい場合のパターンです。
JavaScript
function stripHtmlTags(html) {
return html.replace(/<[^>]*>/g, '');
}
// 使用例
const html = '<h1>タイトル</h1><p>本文の<strong>テキスト</strong>です</p>';
console.log(stripHtmlTags(html));
// "タイトル本文のテキストです"
注意:この正規表現による方法は簡易的なものです。セキュリティ上重要な場面(XSS対策など)では、DOMParser や専用ライブラリを使うことを推奨します。
電話番号のフォーマット
数字だけの電話番号にハイフンを挿入して読みやすくします。
JavaScript
// 携帯電話(090/080/070)のフォーマット
function formatMobilePhone(num) {
return num.replace(/(d{3})(d{4})(d{4})/, '$1-$2-$3');
}
console.log(formatMobilePhone('09012345678'));
// "090-1234-5678"
// 固定電話(03, 06など市外局番2桁)のフォーマット
function formatLandlinePhone(num) {
return num.replace(/(d{2,4})(d{2,4})(d{4})/, '$1-$2-$3');
}
console.log(formatLandlinePhone('0312345678'));
// "03-1234-5678"
郵便番号のフォーマット
JavaScript
function formatPostalCode(code) {
// ハイフンを除去してから再フォーマット
const digits = code.replace(/D/g, '');
return digits.replace(/(d{3})(d{4})/, '〒$1-$2');
}
console.log(formatPostalCode('1000001')); // "〒100-0001"
console.log(formatPostalCode('100-0001')); // "〒100-0001"
数値のカンマ区切り(3桁ごと)
金額表示などで3桁ごとにカンマを挿入するパターンです。
JavaScript
function addCommas(num) {
return String(num).replace(/(d)(?=(d{3})+(?!d))/g, '$1,');
}
console.log(addCommas(1234567890)); // "1,234,567,890"
console.log(addCommas(9800)); // "9,800"
console.log(addCommas(500)); // "500"(3桁以下は変化なし)
正規表現の解説:/(d)(?=(d{3})+(?!d))/g は「後ろに3桁の数字の塊が1つ以上続く数字」に一致します。先読み (?=...) と否定先読み (?!d) を組み合わせた高度なパターンです。
より簡単な方法:実務では Number(1234567).toLocaleString() を使うほうが簡単です。ただし、正規表現版はカスタマイズ性が高い(小数点対応など)というメリットがあります。
改行コードの統一
Windows(
)、旧Mac(
)、Unix(
)の改行コードが混在するテキストを統一します。
JavaScript
function normalizeNewlines(text) {
//
(Windows)と
(旧Mac)をすべて
に統一
return text.replace(/
?/g, '
');
}
// テスト
const mixed = 'Line1
Line2
Line3
Line4';
const result = normalizeNewlines(mixed);
console.log(result.split('
'));
// ["Line1", "Line2", "Line3", "Line4"]
なぜ /
?/g で十分?
(Windows改行)は
の後に
があるパターン。
(旧Mac改行)は
の後に
がないパターン。どちらも
?(
の後に
が0個か1個)にマッチし、
に置換されます。
XSS対策:HTMLエスケープ
ユーザー入力をHTMLに挿入する際に、特殊文字をエスケープしてXSS(クロスサイトスクリプティング)攻撃を防ぎます。
JavaScript
function escapeHtml(str) {
const escapeMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
''': '''
};
return str.replace(/[&<>"']/g, (char) => escapeMap[char]);
}
// 使用例
const userInput = '<script>alert("XSS")</script>';
console.log(escapeHtml(userInput));
// "<script>alert("XSS")</script>"
実行結果
<script>alert("XSS")</script>
重要:innerHTMLでユーザー入力を表示する場合は必ずエスケープしてください。textContentを使う場合はブラウザが自動的にエスケープするため不要です。
余分な空白・改行の除去
JavaScript
// 連続する空白を1つにまとめる
const messy = 'Hello World !';
messy.replace(/s+/g, ' '); // "Hello World !"
// 前後の空白を除去(trim()と同じ動作)
const padded = ' Hello World ';
padded.replace(/^s+|s+$/g, ''); // "Hello World"
// 空行を除去(連続改行を1つにまとめる)
const text = 'Line1
Line2
Line3';
text.replace(/
{2,}/g, '
'); // "Line1
Line2
Line3"
URLの抽出とリンク化
JavaScript
function linkify(text) {
const urlPattern = /(https?://[^s<>"]+)/g;
return text.replace(
urlPattern,
'<a href="$1" target="_blank" rel="noopener">$1</a>'
);
}
// 使用例
const text = '詳細は https://example.com を参照';
console.log(linkify(text));
// '詳細は <a href="https://example.com"...>https://example.com</a> を参照'
キャメルケース ↔ スネークケース変換
JavaScript
// キャメルケース → スネークケース
function camelToSnake(str) {
return str.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());
}
console.log(camelToSnake('firstName')); // "first_name"
console.log(camelToSnake('backgroundColor')); // "background_color"
// スネークケース → キャメルケース
function snakeToCamel(str) {
return str.replace(/_([a-z])/g, (match, c) => c.toUpperCase());
}
console.log(snakeToCamel('first_name')); // "firstName"
console.log(snakeToCamel('background_color')); // "backgroundColor"
replace()の注意点とよくあるミス
replace() は直感的に使えるメソッドですが、いくつかの落とし穴があります。ここではよくあるミスとその対策をまとめます。
ミス1:元の文字列が変更されると思い込む
JavaScript
let text = 'Hello World';
// ❌ 戻り値を使わない → text は変わらない
text.replace('World', 'JavaScript');
console.log(text); // "Hello World"(変わっていない!)
// ✅ 戻り値を変数に代入する
text = text.replace('World', 'JavaScript');
console.log(text); // "Hello JavaScript"
ミス2:正規表現の特殊文字をエスケープし忘れる
JavaScript
// ❌ ピリオドは正規表現では「任意の1文字」
'3.14 + 3x14'.replace(/3.14/g, 'π');
// "π + π"(3x14 も一致してしまう!)
// ✅ バックスラッシュでエスケープ
'3.14 + 3x14'.replace(/3.14/g, 'π');
// "π + 3x14"(正しい結果)
エスケープが必要な特殊文字:. * + ? ^ $ { } ( ) | [ ] ─ これらを文字として検索するには でエスケープしてください。
ミス3:動的な文字列を正規表現にそのまま使う
JavaScript
// ユーザー入力を正規表現に使う場合はエスケープが必要
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[]\]/g, '\$&');
}
// 使用例
const userInput = 'price: $100 (tax)';
const escaped = escapeRegex(userInput);
// "price: \$100 \(tax\)"
const regex = new RegExp(escaped, 'g');
// これで安全に検索・置換できる
ミス4:replaceAll()に正規表現を渡してgフラグを忘れる
前述のとおり、replaceAll() に正規表現を渡す場合はgフラグが必須です。忘れるとTypeErrorが発生します。
ミス5:$の特殊な意味を見落とす
JavaScript
// ❌ 置換文字列の$が特殊パターンとして解釈される
'price'.replace('price', '$100');
// "$100" ではなく "00" になる場合がある($1 がキャプチャ参照と解釈)
// ✅ $$ で $ をリテラルとして挿入
'price'.replace('price', '$$100');
// "$100"
よくある質問(FAQ)
Q. replace()で全ての一致箇所を置換するにはどうすればよいですか?
A. ES2021以降ならreplaceAll("検索", "置換")が使えます。旧来の方法は正規表現にgフラグを付けてstr.replace(/検索/g, "置換")。特殊文字(.、*、?等)を含む文字列をリテラルとして検索する場合はstr.replace(/特殊文字を含む.*/g, "...")でエスケープが必要です。
Q. replace()で正規表現のキャプチャグループを置換後の文字列に使うにはどうすればよいですか?
A. 置換文字列内で$1(1番目のキャプチャグループ)・$2(2番目)のように使えます。例:"2024-04-01".replace(/(\d{4})-(\d{2})-(\d{2})/, "$1年$2月$3日")で”2024年04月01日”になります。関数を渡す場合はキャプチャグループが引数として渡されます。
Q. replace()で大文字・小文字を区別せずに置換するにはどうすればよいですか?
A. 正規表現にiフラグを付けます:str.replace(/hello/gi, "Hi")。gフラグで全箇所、iフラグで大文字小文字を区別しません。replaceAll()はiフラグなしの場合は大文字小文字を区別します。
まとめ:文字列置換メソッド比較表
最後に、JavaScriptで文字列を置換する方法を一覧で比較します。
| メソッド / 手法 |
全置換 |
正規表現 |
コールバック |
対応環境 |
| replace(string, rep) |
最初の1つだけ |
– |
対応 |
全ブラウザ |
| replace(/pattern/g, rep) |
すべて |
対応 |
対応 |
全ブラウザ |
| replaceAll(string, rep) |
すべて |
gフラグ必須 |
対応 |
ES2021〜 |
| split(search).join(rep) |
すべて |
– |
– |
全ブラウザ |
おすすめの使い分け:
- 最初の1つだけ置換 →
replace(string, rep)
- 単純な全置換 →
replaceAll()(ES2021+)または split().join()
- パターンで全置換 →
replace(/regex/g, rep)
- 動的な置換(計算・条件分岐) →
replace(regex, callback)
- ユーザー入力で全置換 →
replaceAll() または split().join()
replace() はJavaScriptの文字列操作で最も使用頻度の高いメソッドの一つです。基本動作(最初の1つだけ置換)を正しく理解し、目的に応じて正規表現・replaceAll()・コールバック関数を使い分けることで、あらゆる文字列置換に対応できます。
特に実務では、HTMLエスケープ、フォーマット変換、テンプレート展開など、replace() + コールバック関数の組み合わせが頻出します。この記事で紹介したパターンをぜひ実際のコードに活用してください。