JavaScript Tips | 文字列ユーティリティ:業務用 - カンマ付与

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「カンマ付与」

ここで作りたいのは、数値や数値っぽい文字列に「3 桁ごとのカンマ」を付けるユーティリティです。

1000 → 1,000
1234567 → 1,234,567
-9876543 → -9,876,543

金額だけでなく、「件数」「数量」「ID(数値)」など、業務画面ではとにかく数字が出てきます。
そのたびに毎回バラバラにフォーマットを書くのではなく、「カンマ付与はこの関数一択」という形にしておくと、コードも見た目も安定します。


カンマ付与の基本ルールを整理する

3 桁ごとに区切る、という約束

やりたいことはシンプルで、「整数部分を右から 3 桁ごとに区切る」ことです。

1 → 1
12 → 12
123 → 123
1234 → 1,234
12345 → 12,345
1234567 → 1,234,567

ここで大事なのは、「右から数える」ということです。
左から 3 桁ではなく、「末尾から 3 桁ずつ区切る」と覚えてください。

マイナス値も普通に出てくる

業務では、マイナスの数値もよく出てきます。

  • 在庫差分 -10
  • 売上差分 -5,000
  • 調整額 -123,456

なので、符号(+/-)と数値部分を分けて考えるのがポイントになります。


一番シンプルな「カンマ付与」関数

数値・文字列どちらも受け取れる formatNumber

まずは、「整数を対象にしたカンマ付与」の基本形を作ります。

function formatNumber(value) {
  if (value == null || value === "") {
    return "";
  }

  const num = Number(value);

  if (!Number.isFinite(num)) {
    return "";
  }

  const sign = num < 0 ? "-" : "";

  const absStr = Math.abs(num).toString();

  const withComma = absStr.replace(/\B(?=(\d{3})+(?!\d))/g, ",");

  return sign + withComma;
}
JavaScript

重要なポイントを一つずつかみ砕く

1. null / 空文字は「何も表示しない」と決める

value == nullnullundefined の両方を拾います。
フォーム入力や API のレスポンスでは、null"" が普通に混ざるので、
ここでは「値がないものは空文字を返す」という方針にしています。

業務によっては「0 を表示したい」ケースもあるので、そこはプロジェクトのルールで調整して構いません。

2. まずは Number に変換して「ちゃんとした数値か」確認する

const num = Number(value);

if (!Number.isFinite(num)) {
  return "";
}
JavaScript

"1000" のような文字列も受け入れたいので、一度 Number(...) で数値に変換します。
NaNInfinity のような「数値としておかしいもの」は、カンマ付与しても意味がないので、空文字を返すようにしています。

ここで「変な値は早めに弾く」ことで、後続の処理がシンプルになります。

3. 符号と絶対値を分けて扱う

const sign = num < 0 ? "-" : "";

const absStr = Math.abs(num).toString();
JavaScript

マイナス値を扱うときは、符号と絶対値を分けるのが鉄板です。

  • sign には "-" または "" を入れる
  • absStr には "1000" のような「符号なしの数字文字列」を入れる

カンマを入れるのは「絶対値の部分」だけにして、最後に符号をくっつける、という流れにすると、ロジックがとても分かりやすくなります。

4. 正規表現で 3 桁ごとにカンマを入れる

const withComma = absStr.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
JavaScript

ここが一番「それっぽくて怖い」ところだと思うので、ちゃんと分解します。

\d{3} は「数字 3 桁」。
(\d{3})+ は「数字 3 桁の塊が 1 回以上続く」。
(?=...) は「先読み」といって、「この位置の右側がこうなっている場所」を探す。
(?!\d) は「この先に数字が続かない位置」。
\B は「単語境界ではない位置」(先頭にはマッチさせないための工夫)。

つまりこの正規表現は、ざっくり言うと、

「先頭以外で、右側に 3 桁の塊が続いていて、そのさらに右に数字が続かない位置」

を探して、そこにカンマを差し込んでいます。

結果として、

“1” → “1”
“12” → “12”
“123” → “123”
“1234” → “1,234”
“12345” → “12,345”
“1234567” → “1,234,567”

という、欲しい動きになります。


実際の動きを例で確認する

典型的なパターン

formatNumber(0);          // "0"
formatNumber(10);         // "10"
formatNumber(100);        // "100"
formatNumber(1000);       // "1,000"
formatNumber(1234567);    // "1,234,567"
formatNumber(-9876543);   // "-9,876,543"
JavaScript

文字列として渡しても動く

formatNumber("1000");       // "1,000"
formatNumber("0012345");    // "12,345"
formatNumber("-5000");      // "-5,000"
JavaScript

Number(...) で数値に変換しているので、
数値っぽい文字列であればそのまま扱えます。


小数を含む数値にカンマを付けたい場合

小数点を分けて考える

小数を含む数値にカンマを付けたい場合は、
「整数部分だけカンマ付与して、小数部分はそのまま残す」という考え方をします。

function formatNumberWithDecimal(value) {
  if (value == null || value === "") {
    return "";
  }

  const num = Number(value);

  if (!Number.isFinite(num)) {
    return "";
  }

  const sign = num < 0 ? "-" : "";

  const absStr = Math.abs(num).toString();

  const [intPart, fracPart = ""] = absStr.split(".");

  const intWithComma = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");

  const result = fracPart ? intWithComma + "." + fracPart : intWithComma;

  return sign + result;
}
JavaScript

どう動くかを確認する

formatNumberWithDecimal(1234.5);      // "1,234.5"
formatNumberWithDecimal(1234.567);    // "1,234.567"
formatNumberWithDecimal(-9876.5);     // "-9,876.5"
formatNumberWithDecimal(1000);        // "1,000"
JavaScript

整数部分だけにカンマが入り、小数部分はそのまま残っているのが分かると思います。


金額フォーマットとの違いと使い分け

「カンマ付与」はもっと汎用的な役割

前にやった「金額フォーマット」は、
「金額としてどう見せるか(小数桁数、マイナス、通貨単位など)」まで含めたユーティリティでした。

今回の「カンマ付与」は、もっと素朴で、「とにかく 3 桁ごとにカンマを入れる」だけの役割です。

だからこそ、使い分けとしてはこうなります。

  • 金額として見せたい → formatCurrency(業務ルール込み)
  • 単に桁を読みやすくしたい → formatNumber / formatNumberWithDecimal

例えば、「件数」「在庫数」「ID」などは formatNumber で十分なことが多いです。


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

「表示用」と「内部計算用」を絶対に混ぜない

カンマ付与した結果は、あくまで「表示用の文字列」です。

これをそのまま計算に使うと、確実にバグります。

const s = formatNumber(1000); // "1,000"

// これは絶対にやってはいけない
Number(s); // NaN になる
JavaScript

計算は必ず「生の数値」で行い、
画面や帳票に出す直前で formatNumber を通す、という流れを徹底してください。

「カンマ付与のルール」を 1 箇所に閉じ込める

画面ごとにバラバラに

value.toLocaleString();
JavaScript

と書き始めると、ロケールや挙動の違いで見た目が揃わなくなります。

だからこそ、

export function formatNumber(value) { ... }
export function formatNumberWithDecimal(value) { ... }
JavaScript

のようなユーティリティを 1 箇所に置いて、

「数字を見せるときは必ずここを通す」

というルールにしておくと、
システム全体の見た目が一気に整います。


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

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

formatNumber(0);
formatNumber(1000);
formatNumber(1234567);
formatNumber(-9876543);

formatNumberWithDecimal(1234.5);
formatNumberWithDecimal(1234.567);
formatNumberWithDecimal(-9876.5);
JavaScript

「どの値がどうフォーマットされるか」
「マイナスや小数がどう扱われるか」

を、自分の目で確認してみてください。

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

export function formatNumber(value) { ... }
export function formatNumberWithDecimal(value) { ... }
JavaScript

を置いて、

数字を表示したくなったら、
生の value をそのまま出すのではなく、
必ずこの“カンマ付与ユーティリティ”を通す、という習慣をつけてみてください。

それだけで、あなたの業務画面の数字は、
「読みづらい生の数字」から、
一目で桁が分かる“業務レベルの数値表示”に変わっていきます。

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