parseInt()
関数を用いて基数変換を行うコードを書いたのですが、意図しない変換をされてしまうことがあったので自分なりの解決策を記録しておきます。
#要約
-
parseInt()
関数は文字列中に指定の基数へ変換できない文字があるとそれ以降の文字列を無視した途中までの解析結果を返す。 -
parseInt()
関数で変換した値を**toString()
メソッドで逆変換を行い、変換前の文字列と比較**する。
#どんなプログラムを書いていたのか
- 文字列を指定の基数の値であるとして、10進数に変換するプログラム。
- 変換できない場合は -1 を返す。
文字列 | 基数 | 出力 |
---|---|---|
AF | 16 | 175 |
100 | 10 | 100 |
101 | 2 | 5 |
Z | 15 | -1 |
AZ | 15 | -1 |
上記の表のように、例えば AF という文字列に 16 の基数が与えられていたならば、AF を16進数の値だとして、10進数に変換するようなプログラムです。 |
||
また、上記の表にある Z や AZ は15進数に存在しない値です。このような入力の場合は、-1 を返します。 |
この問題を解決するために、parseInt()
という便利な関数があります。
これで変換すればよい!と私は考えました。
#parseInt() 関数で変換を試みた
##コード
function f (str, rad) {
var ret_val = parseInt(str, rad);
if (Number.isNaN(ret_val)) {
return -1
}
return ret_val
}
console.log(f("AF",16)); // => 175 correct
console.log(f("100",10));// => 100 correct
console.log(f("101",2)); // => 5 correct
console.log(f("Z", 15)); // => -1 correct
console.log(f("AZ", 15));// => 10 incorrect
15進数の AZ は存在せず、10進数に変換できないので、出力は -1 を期待しますが10が返ってきました。
変換できないのだから、NaN
を返すんじゃないの???
戻り値
与えられた文字列を解析した整数値です。最初の文字を数値に変換できない場合、NaN が返されます。
MDN web docs: parseInt() 構文より引用
これは意図しない返り値です。どうしましょう
#parseInt() 関数の仕様
もう一度、しっかり MDN web docs の parseInt()
のページをチェックしました。
parseInt()関数が第1引数の文字列の中に第2引数の基数で数字とされない文字を認めると、それ以降の文字は無視され、そこまでの値を解析した整数値が返されます。
parseInt()関数は数値を整数に切り捨てます。
第1引数の文字列の前と後の半角スペースは無視されます。
MDN web docs: parseInt() 説明より引用
ここらへんに私が意図しない返り値を返す理由がありそうです。
上記のように、parseInt()
関数は文字列の中に指定した基数に存在しない文字があるとき、それ以降の文字列を無視して解析途中の値を返します。
つまり、AZ
の場合、Z
は15進数に存在しない文字であるため、それまでの解析結果、つまり A
を10進数に変換した値である10が返ってくるということなんですね。
#解決策
10進数に変換した値をもう一度、指定の基数に変換し、入力時の文字列と同値かどうかチェックする。
##コード
function f(str, rad) {
var converted_val = Number.parseInt(str,rad);
var re_converted_val = converted_val.toString(rad).toUpperCase();
if (re_converted_val != str) {
return -1;
}
return converted_val;
}
console.log(f("AF",16)); // => 175 correct
console.log(f("100",10));// => 100 correct
console.log(f("101",2)); // => 5 correct
console.log(f("Z", 15)); // => -1 correct
console.log(f("AZ", 15));// => -1 correct
できました!
先ほど意図しない値を返していた AZ
ですが、converted_val(10)
を toString()
メソッドを用いて、もう一度 15進数(A)
に変換します。
そして、元の文字列(AZ
)と比較し、異なる値であることを確認し、-1を返しています。
#最後に
最後まで変換できないなら途中までの値を返さないで NaN
を返してよ...と思ったのですが、何か事情があるんでしょうか。
道のりは長いですね笑
誤字脱字や解釈の誤りなどございましたら、ご指摘くださると大変ありがたいです。
ここまで読んでくださり、ありがとうございました。