【JavaScript】文字列内の最初の数値を抽出する方法|match・parseIntの違いと小数/マイナス/位置取得まで

「商品ID abc123」や「在庫: 45個」のような文字列から、最初に出てくる数値だけを取り出したい場面があります。JavaScriptでは正規表現を使うのが基本ですが、parseInt との違いを理解しておかないと、想定外の NaN に悩まされます。

この記事の結論:文字列のどこにあっても最初の数値を拾うなら str.match(/\d+/)?.[0]先頭が数値だと分かっているときだけ parseInt(str) が使えます。parseInt先頭からしか読まないため、parseInt("abc123")NaN になる点に注意します。
スポンサーリンク

match() で最初の数値を抽出する(基本)

もっとも確実な方法です。/\d+/(グローバルフラグ g なし)で match() すると、最初に見つかった連続する数字が 配列の0番目に入ります。?.[0] で安全に取り出し、Number() で数値に変換します。

match(/\d+/) で最初の数値
const str = "商品abc123def456";

const first = str.match(/\d+/)?.[0];
console.log(first);          // "123"(文字列)
console.log(Number(first));  // 123(数値)
グローバルフラグ g付けないのがポイントです。g を付けると全件の配列になりますが、最初の1個だけ欲しいときは /\d+/ のままで [0] を取れば十分です。すべての数値が必要なら文字列から数値のみ取得する方法を参照してください。
マッチしないと null数字が1つも無いとき str.match(/\d+/)null を返します。そのまま [0] を付けるとエラーになるため、?.[0](オプショナルチェーン)で受け、必要なら ?? null で既定値を決めます。
数字が無いケース
const str = "数字なし";

console.log(str.match(/\d+/));            // null
console.log(str.match(/\d+/)?.[0] ?? null); // null(安全)

parseInt() は「先頭が数値」のときだけ使える

parseInt(str) は手軽ですが、文字列の先頭から数値として読める部分だけを返します。先頭が数字なら使えますが、数字より前に文字があると NaN になります。

parseInt は先頭限定
console.log(parseInt("123abc"));      // 123(先頭が数値 → OK)
console.log(parseInt("  123abc"));    // 123(先頭の空白は無視される)
console.log(parseInt("abc123def"));   // NaN(先頭が文字 → 取れない!)
よくある誤解:「parseInt は文字列のどこからでも最初の数値を拾う」というのは誤りです。parseInt("abc123")123 ではなく NaN を返します。どこにあっても拾いたいなら match(/\d+/) を使ってください。

小数やマイナス符号を含む最初の数値を取る

\d+ は整数の連続にしかマッチしないため、-3.5 のような値は符号や小数点で切れてしまいます。/-?\d+(?:\.\d+)?/ に広げれば、マイナスや小数を含む最初の数値を取り出せます。

小数・マイナス対応
const str = "気温は-3.5度です";

const first = str.match(/-?\d+(?:\.\d+)?/)?.[0];
console.log(first);         // "-3.5"
console.log(Number(first)); // -3.5

最初の数値の位置(index)も取得する

g フラグなしの match() の戻り値には、マッチした位置 index が含まれます。「何文字目から数値が始まるか」を知りたいときに使えます。

match.index で位置を取得
const str = "abc123def";

const m = str.match(/\d+/);
console.log(m[0]);     // "123"
console.log(m.index);  // 3(0始まりで4文字目から)

1文字ずつ処理する方法と落とし穴

正規表現を使わず1文字ずつ調べることもできますが、2つの落とし穴があります。①最初の数字を見つけて即 break すると1桁しか取れない"abc123""1" になる)、②!isNaN(c) で判定すると isNaN(" ")false のため空白を数字とみなす。この2点を直したのが次のコードです。

OK: 連続する桁をまとめて取る
const str = "abc123def456";
let buf = "";
let first = null;
for (const c of str) {
  if (c >= "0" && c <= "9") {   // 範囲で判定(空白に惑わされない)
    buf += c;                   // 連続する桁をためる
  } else if (buf !== "") {
    first = buf;                // 数字が途切れたら確定
    break;
  }
}
if (first === null && buf !== "") first = buf; // 末尾で終わるケース
console.log(first); // "123"
見てのとおり手書きの反復処理は長くなりがちです。特別な事情がなければ str.match(/\d+/)?.[0] の1行で十分です。

方法の使い分け

状況 書き方
どこにあっても最初の数値(推奨) str.match(/\d+/)?.[0]
先頭が数値だと分かっている parseInt(str)
小数・マイナスも含める str.match(/-?\d+(?:\.\d+)?/)?.[0]
出現位置も知りたい str.match(/\d+/).index
すべての数値が欲しい str.match(/\d+/g)

実用例:商品名から最初の数量を取り出す

「お徳用12個入りセット」から数量
const name = "お徳用12個入りセット";

const qty = Number(name.match(/\d+/)?.[0] ?? 0);
console.log(qty); // 12

よくある質問(FAQ)

Q文字列の途中にある最初の数値を取り出すには?
Astr.match(/\d+/)?.[0] を使います。位置に関係なく最初の連続した数字を返します。数値型にしたいときは Number(...) で囲み、数字が無い場合に備えて ?.[0] ?? null のようにガードします。
QparseInt で最初の数値が取れないのはなぜ?
AparseInt文字列の先頭からしか数値を読まないためです。parseInt("abc123") は先頭が a なので NaN になります。先頭が数字("123abc")なら 123 が取れます。どこにあっても拾いたいときは match(/\d+/) を使ってください。
Q小数やマイナスの最初の数値を取りたい場合は?
A/-?\d+(?:\.\d+)?/ を使います。-? でマイナス符号、(?:\.\d+)? で小数部に対応します。"気温は-3.5度" から -3.5 が取り出せます。
Q最初の数値が何文字目から始まるか知りたい。
Ag フラグなしの match() の戻り値の index プロパティを見ます。"abc123".match(/\d+/).index3(0始まり)です。

まとめ

JavaScriptで文字列内の最初の数値を抽出する方法のポイントを整理します。

  • 基本は str.match(/\d+/)?.[0](位置に関係なく拾える)
  • parseInt(str)先頭が数値のときだけ"abc123"NaN
  • 小数・マイナスは /-?\d+(?:\.\d+)?/
  • 位置は match(...).index で取得
  • 反復処理は「1桁で break」「isNaN で空白誤判定」に注意

関連として、文字列から数値のみ取得する方法(すべて)文字列内の最後にある数値を取得する方法文字列を数値型に変換する方法もあわせて確認すると、数値の扱いに強くなれます。