【JavaScript】文字列を数値に変換できるか判定する方法|Number.isFiniteで空文字・全角・Infinityの罠を防ぐ堅牢な判定

フォーム入力などで受け取った文字列を計算に使う前に、そもそも数値に変換できる文字列なのかを判定したい場面はよくあります。ところが JavaScript の判定にはいくつもの落とし穴があり、安易に isNaN() を使うと空文字や空白を「数値」と誤判定してしまいます。

この記事では、なぜ素の isNaN() / Number() だけではダメなのかを示したうえで、Number.isFinite()trim() を組み合わせた堅牢な判定、整数限定の判定、正規表現での形式チェックまで解説します。

この記事の結論(堅牢な判定):value.trim() !== "" && Number.isFinite(Number(value)) が決定版です。空文字・空白・Infinity・全角数字をすべて正しく弾けます。
スポンサーリンク

結論:堅牢な判定関数

まず推奨する判定関数を示します。これ1つで主要な落とし穴をカバーできます。

isNumeric(推奨)
function isNumeric(value) {
  // 文字列以外・空文字・空白だけは「数値でない」
  if (typeof value !== "string" || value.trim() === "") return false;
  // 数値化して「有限の数」かを判定(NaN も Infinity も除外)
  return Number.isFinite(Number(value));
}

console.log(isNumeric("123"));      // true
console.log(isNumeric("-12.5"));    // true
console.log(isNumeric("1e3"));      // true(指数表記もOK)
console.log(isNumeric(""));         // false(空文字)
console.log(isNumeric("   "));      // false(空白だけ)
console.log(isNumeric("12px"));     // false
console.log(isNumeric("Infinity")); // false(無限大は除外)
console.log(isNumeric("123"));     // false(全角数字)

なぜ素の isNaN() だけではダメなのか

判定でよく使われる !isNaN(value) には大きな穴があります。isNaN() は引数を内部で Number() に変換してから判定するため、空文字や空白が 0 に変換されて「数値」と判定されてしまうのです。

NG: !isNaN() の落とし穴
console.log(!isNaN("123"));      // true
console.log(!isNaN(""));         // true  ← 空文字なのに「変換可能」!
console.log(!isNaN("   "));      // true  ← 空白だけでも true(0 扱い)
console.log(!isNaN("Infinity")); // true  ← 無限大も通ってしまう
空文字・空白・Infinity が通ってしまうのが !isNaN() の問題です。これらを弾くには value.trim() !== "" のチェックと、isNaN() ではなく Number.isFinite() を使うことが重要です。

Number.isFinite() で判定する(推奨)

Number.isFinite() は「有限の数値か」を判定します。NaN はもちろん Infinityfalse になるため、isNaN() より厳密です。文字列を Number() で数値化してから渡します。

Number.isFinite(Number(value))
console.log(Number.isFinite(Number("123")));      // true
console.log(Number.isFinite(Number("12px")));     // false(NaN)
console.log(Number.isFinite(Number("Infinity"))); // false(無限大を除外)
console.log(Number.isFinite(Number("")));         // true  ← 空文字は0なので注意!
Number.isFinite(Number(""))0 経由で true になります。そのため必ず先に value.trim() !== "" で空文字・空白を弾く必要があります(上の isNumeric() がその形です)。なお文字列を数値に変換する方法そのものは文字列を数値型に変換する方法を参照してください。

整数だけを許可したい場合

小数を除いて整数だけを通したいときは Number.isInteger() を使います。

整数のみ判定
function isIntegerString(value) {
  if (typeof value !== "string" || value.trim() === "") return false;
  return Number.isInteger(Number(value));
}

console.log(isIntegerString("123"));  // true
console.log(isIntegerString("12.5")); // false(小数)
console.log(isIntegerString("12px")); // false
console.log(isIntegerString(""));     // false

正規表現で「形式」を厳密に判定する

「変換できるか」ではなく「見た目が数値の形式か」を厳密に判定したい場合は正規表現が有効です。16進数(0x1F)や指数表記(1e3)をあえて弾きたいときに使います。

正規表現で形式を判定
// 整数または小数(先頭の符号は許可、指数・16進は不可)
function isNumericFormat(s) {
  return /^-?\d+(\.\d+)?$/.test(s);
}

console.log(isNumericFormat("123"));   // true
console.log(isNumericFormat("-12.5")); // true
console.log(isNumericFormat("1e3"));   // false(指数表記は対象外)
console.log(isNumericFormat("0x1F"));  // false(16進は対象外)
console.log(isNumericFormat("12px"));  // false
console.log(isNumericFormat(""));      // false
正規表現は「数値の形式かどうか」を見るもので、Number() で変換できるか(指数・16進を含む)とは判定基準が異なります。「人が入力した10進数の形式だけ通したい」場合は正規表現、「JSの数値として解釈できれば良い」場合は isNumeric() と、目的で使い分けてください。

手法ごとの判定結果の違い

同じ入力でも手法によって結果が変わります。とくに空文字・空白・Infinityに注目してください。

入力 !isNaN(x) isFinite(Number(x)) isNumeric(x)(推奨)
"123" true true true
""(空文字) true(誤判定) true(誤判定) false
" "(空白) true(誤判定) true(誤判定) false
"12px" false false false
"1e3" true true true
"Infinity" true(誤判定) false false
"123"(全角) false false false
!isNaN() は空文字・空白・Infinity を取りこぼします。isNumeric()trimNumber.isFinite)なら、これらをすべて正しく false にできます。

全角数字・カンマなどの注意点

全角数字「123」やカンマ区切り「1,000」は Number()NaN になるため「変換不可」と判定されます。これらを数値として扱いたい場合は、判定の前に正規化・除去します。

全角・カンマを正規化してから判定
function normalize(s) {
  return s
    .replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) - 0xFEE0)) // 全角→半角
    .replace(/,/g, ""); // カンマ除去
}

console.log(isNumeric(normalize("123")));   // true
console.log(isNumeric(normalize("1,000")));  // true

実用例:フォーム入力のバリデーション

入力値の数値チェック
const input = document.getElementById("amount");

input.addEventListener("blur", () => {
  if (!isNumeric(input.value)) {
    console.log("数値を入力してください");
    input.classList.add("error");
  } else {
    input.classList.remove("error");
    const amount = Number(input.value);
    console.log("税込:", Math.round(amount * 1.1));
  }
});

よくある質問(FAQ)

Q文字列が数値に変換できるか判定する一番安全な方法は?
Avalue.trim() !== "" && Number.isFinite(Number(value)) です。空文字・空白を trim で弾き、Number.isFiniteNaNInfinity の両方を除外できます。
Qなぜ isNaN() だけでは不十分なのですか?
AisNaN() は引数を Number() で変換してから判定するため、Number("")Number(" ")0 になり、!isNaN("")true(=変換可能)になってしまうからです。また Infinity も通します。Number.isFinite()trim() で対策します。
QisNaN() と Number.isFinite() はどう違いますか?
AisNaN(x) は「NaN かどうか」だけを見ます(Infinity は通す)。Number.isFinite(x) は「有限の数か」を見るので、NaNInfinity の両方を false にできます。数値判定には Number.isFinite() の方が安全です。
Q全角数字「123」を数値として判定したいのですが?
ANumber("123")NaN になるため、そのままでは「変換不可」と判定されます。replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) - 0xFEE0)) で半角に正規化してから isNumeric() に渡してください。

まとめ

JavaScriptで文字列が数値に変換できるか判定する方法のポイントを整理します。

  • 決定版は value.trim() !== "" && Number.isFinite(Number(value))
  • !isNaN() は空文字・空白・Infinity を誤って通すので単体では使わない
  • 整数限定は Number.isInteger(Number(value))(+空文字チェック)
  • 10進数の形式だけ通したいなら正規表現 /^-?\d+(\.\d+)?$/
  • 全角数字・カンマは NaN → 判定前に正規化・除去する

あわせて文字列を数値型に変換する方法文字列が数値であるかを判定する方法文字列から数値だけを取り出す方法も確認すると理解が深まります。