JavaScript Tips | 文字列ユーティリティ:検索・置換 - 全置換

JavaScript JavaScript
スポンサーリンク

「全置換」って何をするユーティリティ?

まずイメージからいきましょう。
「この文字列の中にある foo を、全部 bar に変えたい」という場面、よくありますよね。

"foo foo foo" → "bar bar bar"
"2024/01/01" の "/" を全部 "-" にしたい → "2024-01-01"
" "(全角スペース)を全部 " "(半角スペース)にしたい

こういう「出てくる全部を置き換える」のが「全置換」です。
逆に、「最初の1個だけ置き換える」のは「単一置換」です。

業務では、ログ整形・CSV 整形・フォーマット変換・マスク処理など、
「同じパターンを全部置き換えたい」場面が本当に多いので、
“全置換ユーティリティ”を一つ持っておくとかなり便利です。


JavaScript 標準の replace と replaceAll の基本

まずは replace の落とし穴

JavaScript には String.prototype.replace があります。

const s = "foo foo foo";
const r = s.replace("foo", "bar");

console.log(r); // "bar foo foo"
JavaScript

ここで重要なのは、replace は「最初の1箇所だけ」しか置き換えないということです。
「全部置き換えたい」と思っているのに、1個しか変わらない——これが初心者が最初にハマるポイントです。

replaceAll なら「全部」置き換えられる

最近の JavaScript には replaceAll があります。

const s = "foo foo foo";
const r = s.replaceAll("foo", "bar");

console.log(r); // "bar bar bar"
JavaScript

これは名前の通り、「一致したところを全部置き換える」メソッドです。
モダンな環境(最近のブラウザ・Node.js)なら、まずこれでOKです。


正規表現+g フラグで「全置換」する方法

replaceAll がない環境でも「全置換」はできる

古い環境や、replaceAll がまだ使えない状況では、
正規表現+g フラグを使って全置換を実現します。

const s = "foo foo foo";
const r = s.replace(/foo/g, "bar");

console.log(r); // "bar bar bar"
JavaScript

/foo/gg は「global(全体)」の意味で、
「文字列全体を対象に、マッチしたところを全部置き換える」という指定です。

ここでの重要ポイント

全置換をしたいときに、
replace("foo", "bar") と書いてしまうと「1個だけ」しか変わらない。
replaceAll("foo", "bar")replace(/foo/g, "bar") を使うと「全部」変わる。

この違いを、頭ではなく「手で動かして体で覚える」と強いです。


全置換ユーティリティを自作する

文字列パターン用のシンプルなユーティリティ

まずは「単純な文字列を全部置き換える」ユーティリティから。

function replaceAllString(text, search, replacement) {
  if (text == null) return "";
  if (search == null || search === "") return String(text); // 空検索はそのまま返す

  const s = String(text);
  const target = String(search);
  const repl = String(replacement);

  // 正規表現の特殊文字をエスケープ
  const escaped = target.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

  const regex = new RegExp(escaped, "g");
  return s.replace(regex, repl);
}
JavaScript

ここが少し大事なので、噛み砕きます。

text が null / undefined でも落ちないようにしている。
search が空文字のときは、そのまま返す(無限にマッチしてしまうのを防ぐ)。
search をそのまま正規表現に入れると、.* などが「特別な意味」を持ってしまう。
それを防ぐために、[.*+?^${}()|[\]\\]\ でエスケープしている。
new RegExp(escaped, "g") で「全体を対象にした正規表現」を作り、replace で全置換している。

これで、次のように使えます。

replaceAllString("foo foo foo", "foo", "bar"); // "bar bar bar"
replaceAllString("2024/01/01", "/", "-");      // "2024-01-01"
replaceAllString("a.b.c", ".", "-");           // "a-b-c"(. も安全に置換できる)
JavaScript

正規表現をそのまま使いたい場合

「数字だけを全部消したい」「連続する空白を1個にしたい」など、
パターンで置き換えたいときは、正規表現をそのまま受け取るユーティリティもありです。

function replaceAllRegex(text, pattern, replacement) {
  if (text == null) return "";
  if (!(pattern instanceof RegExp)) {
    throw new Error("pattern は RegExp である必要があります");
  }

  const s = String(text);

  // g フラグが付いていない場合は付け直す
  const flags = pattern.flags.includes("g")
    ? pattern.flags
    : pattern.flags + "g";

  const regex = new RegExp(pattern.source, flags);

  return s.replace(regex, replacement);
}
JavaScript

使い方はこうです。

replaceAllRegex("abc123def456", /\d+/g, "");   // "abcdef"
replaceAllRegex("a   b    c", /\s+/g, " ");    // "a b c"
JavaScript

業務での具体的な使いどころ

日付フォーマットの変換

API から "2026/02/19" のような日付文字列が来て、
画面では "2026-02-19" として表示したい、というのはよくあります。

function normalizeDateFormat(dateStr) {
  return replaceAllString(dateStr, "/", "-");
}

normalizeDateFormat("2026/02/19"); // "2026-02-19"
JavaScript

全角スペース・タブなどの整理

入力値の中に、全角スペースやタブが混ざっていることがあります。
それを全部「半角スペース1個」にそろえたい。

function normalizeSpaces(text) {
  if (text == null) return "";

  // 全角スペースを半角に
  let s = replaceAllString(text, " ", " ");

  // 連続する空白を1個に
  s = replaceAllRegex(s, /\s+/g, " ");

  return s.trim();
}

normalizeSpaces("  山田 太郎   "); // "山田 太郎"
JavaScript

マスク処理(個人情報の一部を隠す)

例えば、メールアドレスのユーザー名部分を * にしたいとします。

function maskEmail(email) {
  if (email == null) return "";

  const [user, domain] = String(email).split("@");
  if (!domain) return email;

  const maskedUser = user.replace(/./g, "*"); // 全文字を * に
  return `${maskedUser}@${domain}`;
}

maskEmail("taro@example.com"); // "****@example.com"
JavaScript

ここでは replace(/./g, "*") で「全置換」を使っています。


設計として意識してほしいこと

「全置換」と「単一置換」を意識的に使い分ける

一番大事なのは、
「今やりたいのは“最初の1個だけ”なのか、“全部”なのか」を意識することです。

replace は「1個だけ」。
replaceAll / 正規表現+g は「全部」。

ここを曖昧にしたまま書き始めると、
「一部だけ変わって残りがそのまま」というバグを生みやすくなります。

「検索パターンのエスケープ」をユーティリティに閉じ込める

replaceAllString の中でやったように、
.* などの正規表現の特殊文字をエスケープする処理は、
毎回自分で書くとほぼ確実にミスります。

なので、

「文字列としての検索パターンを全部置き換えたい」 → replaceAllString
「正規表現としてのパターンを使いたい」 → replaceAllRegex

のように、用途ごとにユーティリティを分けておくと安全です。


ちょっとだけ手を動かしてみる

コンソールで、次のあたりを試してみてください。

"foo foo foo".replace("foo", "bar");
"foo foo foo".replaceAll("foo", "bar");
"2024/01/01".replaceAll("/", "-");

replaceAllString("a.b.c", ".", "-");
replaceAllRegex("a   b    c", /\s+/g, " ");
JavaScript

「どこまでが変わって、どこが変わらないか」を目で確認すると、
「単一置換」と「全置換」の違いがかなりクリアになります。

そのうえで、自分のプロジェクトに

export function replaceAllString(text, search, replacement) { ... }
export function replaceAllRegex(text, pattern, replacement) { ... }
JavaScript

を一つ置いて、
「“全部置き換えたい”ときは必ずここを通す」
というルールにしてみてください。

それができた瞬間、あなたの文字列置換は
「なんとなく replace を呼んでいる状態」から
「意図を持って全置換をコントロールしている状態」に、一段レベルアップします。

タイトルとURLをコピーしました