JavaScript Tips | 文字列ユーティリティ:業務用 - 桁数制限

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「桁数制限」

ここでの「桁数制限」は、数値や数値文字列の「桁数」をルール通りに制限するユーティリティです。

例えば、こんな要件がよくあります。

  • 金額は「整数 9 桁まで、小数 2 桁まで」にしたい
  • 重量は「整数 5 桁まで、小数 3 桁まで」にしたい
  • 入力欄に「最大 10 桁までの数値」しか入れさせたくない

これを毎回バラバラに if 文で書くのではなく、
「桁数制限はこの関数に任せる」という形にしておくと、業務コードがかなりスッキリします。


まずは「整数桁数の制限」を考える

整数部分の桁数を制限するイメージ

例えば、「整数部分は最大 5 桁まで」というルールを考えます。

  • 12345 → OK(そのまま)
  • 123456 → NG(6 桁なので 5 桁に切る or エラー)

ここで大事なのは、「どう制限するか」を決めることです。

  • はみ出した分を切り捨てる(12345612345
  • はみ出したら null を返す(「不正な値」として扱う)

どちらもありですが、ここでは「切り詰める版」を作ってみます。

整数桁数を制限する関数

function limitIntegerDigits(value, maxDigits) {
  if (value == null || value === "") {
    return "";
  }

  const str = String(value).trim();

  const sign = str.startsWith("-") ? "-" : "";
  const unsigned = sign ? str.slice(1) : str;

  const digitsOnly = unsigned.replace(/\D/g, "");

  if (!digitsOnly) {
    return sign ? sign + "0" : "0";
  }

  const limited = digitsOnly.slice(0, maxDigits);

  return sign + limited;
}
JavaScript

重要ポイントをかみ砕いて説明する

ここは業務でよく使うので、丁寧に見てください。

最初に、値を文字列にして前後の空白を削ります。

const str = String(value).trim();
JavaScript

次に、符号(マイナス)と本体を分けます。

const sign = str.startsWith("-") ? "-" : "";
const unsigned = sign ? str.slice(1) : str;
JavaScript

"-12345" のような文字列から、sign = "-"unsigned = "12345" のように分けておきます。
こうしておくと、「桁数制限は符号なしの部分だけに適用する」ことができます。

次に、「数字だけ」を取り出します。

const digitsOnly = unsigned.replace(/\D/g, "");
JavaScript

\D は「数字以外」を意味するので、
replace(/\D/g, "") は「数字以外を全部消す」という意味になります。

"12,345""12345"
"1 234""1234"

のように、「見た目用のカンマやスペース」が混ざっていても、数字だけを取り出せます。

数字が一つもなければ、0 とみなします。

if (!digitsOnly) {
  return sign ? sign + "0" : "0";
}
JavaScript

最後に、桁数制限をかけます。

const limited = digitsOnly.slice(0, maxDigits);

return sign + limited;
JavaScript

slice(0, maxDigits) で、先頭から maxDigits 桁だけを残します。
例えば maxDigits = 5 のとき、"123456""12345" になります。


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

limitIntegerDigits("123456", 5);      // "12345"
limitIntegerDigits("00123456", 5);    // "00123"
limitIntegerDigits("-987654", 3);     // "-987"
limitIntegerDigits("12,345,678", 4);  // "1234"
limitIntegerDigits("", 5);            // ""
JavaScript

「符号はそのまま」「数字だけを抜き出して」「桁数を切り詰める」という動きになっているのが分かると思います。


小数を含む「整数桁+小数桁」の制限

よくある業務ルールの形

例えば、こんなルールがよくあります。

  • 整数部分は最大 5 桁
  • 小数部分は最大 2 桁

この場合、次のような挙動にしたいことが多いです。

  • 12345.67 → OK(そのまま)
  • 123456.78 → 整数が 6 桁なので 12345.78 に切る or エラー
  • 123.4567 → 小数が 4 桁なので 123.45 に切る

ここでも、「切り詰める版」を作ってみます。

整数桁+小数桁を制限する関数

function limitDecimalDigits(value, maxIntegerDigits, maxFractionDigits) {
  if (value == null || value === "") {
    return "";
  }

  const str = String(value).trim();

  const sign = str.startsWith("-") ? "-" : "";
  const unsigned = sign ? str.slice(1) : str;

  const normalized = unsigned.replace(/,/g, "");

  const parts = normalized.split(".");
  const intPartRaw = parts[0] || "0";
  const fracPartRaw = parts[1] || "";

  const intDigits = intPartRaw.replace(/\D/g, "") || "0";
  const fracDigits = fracPartRaw.replace(/\D/g, "");

  const limitedInt = intDigits.slice(0, maxIntegerDigits);
  const limitedFrac = fracDigits.slice(0, maxFractionDigits);

  let result = limitedInt;
  if (maxFractionDigits > 0 && limitedFrac) {
    result += "." + limitedFrac;
  }

  return sign + result;
}
JavaScript

重要ポイントを深掘りする

まず、符号を分けるところまではさっきと同じです。

const sign = str.startsWith("-") ? "-" : "";
const unsigned = sign ? str.slice(1) : str;
JavaScript

次に、カンマを消して「素の数値文字列」にします。

const normalized = unsigned.replace(/,/g, "");
JavaScript

"12,345.67""12345.67" のように、見た目用のカンマを取り除きます。

次に、小数点で分割します。

const parts = normalized.split(".");
const intPartRaw = parts[0] || "0";
const fracPartRaw = parts[1] || "";
JavaScript

"12345.67"["12345", "67"]
"12345"["12345"](小数部分は空)

整数部分と小数部分を分けて扱えるようにします。

そのうえで、「数字だけ」を取り出します。

const intDigits = intPartRaw.replace(/\D/g, "") || "0";
const fracDigits = fracPartRaw.replace(/\D/g, "");
JavaScript

整数部分に数字が一つもなければ "0" とみなします。
小数部分は、数字がなければ空文字のままです。

ここから、桁数制限をかけます。

const limitedInt = intDigits.slice(0, maxIntegerDigits);
const limitedFrac = fracDigits.slice(0, maxFractionDigits);
JavaScript

整数部分は maxIntegerDigits 桁まで、小数部分は maxFractionDigits 桁までに切り詰めます。

最後に、結果を組み立てます。

let result = limitedInt;
if (maxFractionDigits > 0 && limitedFrac) {
  result += "." + limitedFrac;
}

return sign + result;
JavaScript

小数桁数の上限が 0 のときは小数点を付けません。
小数部分が空のときも、小数点は付けません。


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

limitDecimalDigits("12345.67", 5, 2);        // "12345.67"
limitDecimalDigits("123456.78", 5, 2);       // "12345.78"
limitDecimalDigits("123.4567", 5, 2);        // "123.45"
limitDecimalDigits("-12,345.6789", 5, 3);    // "-12345.678"
limitDecimalDigits("abc123.45xyz", 5, 2);    // "123.45"
JavaScript

「整数桁」「小数桁」を別々に制限していること、
符号やカンマがあってもちゃんと処理できていることが分かると思います。


「桁数制限」と「丸め」の違いを意識する

ここで作っているのは、「切り詰める」桁数制限です。

123.4567 を小数 2 桁にするとき、
桁数制限 → 123.45(3 桁目以降を切り捨て)
小数丸め(四捨五入) → 123.46

という違いがあります。

業務要件によって、

  • 「単純に桁数を切り詰めたい」 → 桁数制限
  • 「正しく四捨五入したい」 → 小数丸め

と使い分ける必要があります。

もし「桁数制限+丸め」のような要件があるなら、

  1. まず roundDecimal で丸める
  2. その結果に対して limitDecimalDigits で桁数制限をかける

という二段構えにすると、意図がはっきりします。


実務で意識してほしい設計のポイント

一つ目は、「入力制御」と「内部制御」を分けることです。
入力欄で「最大 10 桁まで」と制限するのと、
内部で「整数 9 桁まで、小数 2 桁まで」と制限するのは、別の話です。

入力側では limitIntegerDigits / limitDecimalDigits を使って「入力値を整形」し、
内部では「丸め」や「バリデーション」と組み合わせて、
「保存してよい値かどうか」を判断する、という設計にすると安全です。

二つ目は、「桁数のルールを一箇所に閉じ込める」ことです。
画面ごとに「ここは 5 桁」「あっちは 6 桁」とバラバラに書き始めると、
どこかでルールが食い違います。

例えば、

export const AMOUNT_INTEGER_DIGITS = 9;
export const AMOUNT_FRACTION_DIGITS = 2;
JavaScript

のような定数を用意しておき、
limitDecimalDigits(value, AMOUNT_INTEGER_DIGITS, AMOUNT_FRACTION_DIGITS)
のように使うと、「どこでも同じルール」が保証しやすくなります。


少し手を動かして感覚をつかむ

コンソールで、次のようなコードを実際に打ってみてください。

limitIntegerDigits("123456", 5);
limitIntegerDigits("-987654", 3);
limitIntegerDigits("12,345,678", 4);

limitDecimalDigits("12345.67", 5, 2);
limitDecimalDigits("123456.78", 5, 2);
limitDecimalDigits("123.4567", 5, 2);
limitDecimalDigits("-12,345.6789", 5, 3);
JavaScript

「どこまでが残って、どこからが切り捨てられるか」
「符号やカンマがどう扱われるか」

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

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

export function limitIntegerDigits(...) { ... }
export function limitDecimalDigits(...) { ... }
JavaScript

を置き、「桁数を制限したくなったら必ずここを通す」というルールを作ってみてください。
それだけで、あなたの数値入力・表示は、場当たり的な if 文の集まりから、
意図と一貫性を備えた「業務レベルの桁数制限ユーティリティ」に変わっていきます。

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