JavaScriptで、文字列を整数としてパースする方法としてparseInt(n, 10)
があります。この投稿では、n
にどんな値を与えたらどんな戻り値になるのかを具体例をもとに検証していきます。
parseInt
の基本的なこと
parseInt
は第1引数に文字列の値を取ることができ、それを整数値のnumber
型に変換する関数です。第2引数は、基数を指定します。基数は省略可能で、省略した場合は第1引数がどんな文字列で始まるかで基数を仮定します。例えば、"0x"
始まりなら16
、"0"
始まりなら8
といった具合にです。第2引数は極力指定するほうが良いとされています。parseInt
で整数と解釈できなかった場合はNaN
が戻り値になります。
parseInt
の詳細については次のMDNのドキュメントをご覧ください。
parseInt
の仕様書を確認したい方は、次のECMAScript 2022の仕様書をご覧ください。
parseInt(n, 10)
に様々な文字列を与えてみる
ここからはparseInt(n, 10)
に様々な文字列を与えてみて、どのような戻り値になるか見ていきます。
まず、テストを手軽に行いたいので、次のようなテスト実行関数を作っておきます。この関数test
は、引数cases
に文字列配列を与えると、入力とパース結果の表が出力されるようになっています。
function test(cases) {
console.table(cases.map((value) => [value, parseInt(value, 10)]));
}
符号
まず、符号がどう扱われるか見てみます。
test(["-1", "-0", "0", "1", "+0", "+1"]);
入力 | 結果 |
---|---|
'-1' |
-1 |
'-0' |
-0 |
'0' |
0 |
'1' |
1 |
'+0' |
0 |
'+1' |
1 |
1文字目が負の符号の場合は、負の整数としてパースされます。JavaScriptは0にも符号がつけられるので、"-0"
は-0
になります。
小数
次に小数です。
test(["-1.2", "-0.1", "-0.0", "0.0", "0.1", "1.2", "+0.0", "+0.1", "+1.2"]);
入力 | 結果 |
---|---|
'-1.2' |
-1 |
'-0.1' |
-0 |
'-0.0' |
-0 |
'0.0' |
0 |
'0.1' |
0 |
'1.2' |
1 |
'+0.0' |
0 |
'+0.1' |
0 |
'+1.2' |
1 |
小数風の文字列は.
以降が無視されるような振る舞いです。
数字に続く数字以外の文字
test(["0px", "-0px", "1px", "-1px"]);
入力 | 結果 |
---|---|
'0px' |
0 |
'-0px' |
-0 |
'1px' |
1 |
'-1px' |
-1 |
文字列が数字で始まっている場合、数字じゃない文字に出くわすまで整数としてパースされます。
桁区切り文字
ES2021からはnumeric separatorという文法が追加されて、numberリテラルに桁の区切りを書けるようになりました。桁の区切り文字は_
です。例えば、1000
と1_000
は同じ値になります。parseInt
ではnumeric separator風の文字列を扱えるのか試します。
test(["123_456", "123,456"]);
入力 | 結果 |
---|---|
'123_456' |
123 |
'123,456' |
123 |
これもやはり、数字以外の文字に出会うとそこでパースをやめます。
bigint風の文字列
ES2020からはbigint型が追加されました。bigintはリテラル表記で数字の末尾にn
を書く形式です。例えば、100n
はbigint型の100
になります。parseInt
ではbigintリテラル風の文字列がどう扱われるのでしょうか。
test(["1n", "1000n"]);
入力 | 結果 |
---|---|
'1n' |
1 |
'1000n' |
1000 |
末尾のnは単純に無視されます。
0始まりの数字
0で始まる数字を見ていきます。
test(["05", "005", "050", "00", "00500px"]);
入力 | 結果 |
---|---|
'05' |
5 |
'005' |
5 |
'050' |
50 |
'00' |
0 |
'00500px' |
500 |
文字列のはじめにある0は無視されます。
前後に空白文字がある数字
前後に空白文字が入っている数字はどうでしょうか。
test([" 1 ", "\n1\n", "\t1\t"]);
入力 | 結果 |
---|---|
' 1 ' |
1 |
'\n1\n' |
1 |
'\t1\t' |
1 |
数字の前後の空白は取り除かれた上でパースされます。
NaNになる文字列
最後に結果がNaN
、つまりパース失敗になるケースを見ていきます。
test(["", "a", "-", "+", "a0", "a1", "a1b"]);
入力 | 結果 |
---|---|
'' |
NaN |
'a' |
NaN |
'-' |
NaN |
'+' |
NaN |
'a0' |
NaN |
'a1' |
NaN |
'a1b' |
NaN |
空白文字やそもそも数字を含んでいないのはNaN
になります。数字を含んでいても、-
と+
を以外の文字で始まる文字列はNaN
になります。
確認した振る舞いのまとめ
parseInt(n, 10)
は
- 正負の符号は解釈される
- 前後の空白文字は取り除かれた上で、パースされる
- 1文字目が数字じゃないと
NaN
になる - 1文字目が数字なら、途中に数字以外が入っていても
NaN
にはならず、数字が続くところまでパースされる
という振る舞い確認されました。
所感
ユースケースによりますが、ユーザーの入力に対してparseInt(n, 10)
をかけるときは、その前にn
に対して正規表現で/^\d+$/
などのチェックをしたほうが、成り行き感がなくなるのでより安心だと思いました。