JavaScriptの動かないコード (初級編) 数値判定の方法・・・入力値が有効な整数かどうかチェック
クイズ…下記のJavaScriptコードが,意図した動作をしないのはどうしてですか。(制限時間1分)
やりたい事
- フォーム上で,テキストボックスに整数を入力してもらう。
- 有効な整数かどうか,ページ上でバリデーションを行なう。
<input type="text" id="my_num"> <input type="button" onClick="f()" value="数値チェック"> <script language="JavaScript"> function f() { var str_num = my_num.value; if ( isNaN( parseInt( str_num ) ) || isNaN( str_num ) ) { alert("有効な整数ではありません。"); } else { alert("OK"); // 有効な整数が入力された } } </script>
発生する不具合
これだと," 1" (数字の前にスペースが入った文字列) や, "01" が通過してしまう。
- isNaN( num )は,
- "" を通してしまう。
- " " を通してしまう。
- " 1" を通してしまう。
- "01" を通してしまう。
- "1a" は通さない。
- isNaN( parseInt( num ) )は,
- " 1" を通してしまう。
- "01" を通してしまう。
- "1a" を通してしまう。
- "1+1" を通してしまう。
- "" は通さない。
- " " は通さない。
落とし穴は,
- isNaN()が空文字列やスペース単体を通してしまう事と,
- parseInt()が文字列の途中で整数変換をやめてしまう事
か。
修正案
これを避けるためには,下記のように書く方法がある。
<input type="text" id="my_num"> <input type="button" onClick="f()" value="数値チェック"> <script language="JavaScript"> function f() { var str_num = my_num.value; if ( str_num.match(/[^0-9]/g) // "", " ", " 1", "1a" をはじく。 // 単体では,"01" を通してしまう || parseInt(str_num, 10) + "" != str_num // "01", "1 " など0付き・スペース付き文字列をはじく。 // 単体では,スペースのみの文字列は通してしまう ) { alert("有効な整数ではありません。"); } else { alert("OK"); // 有効な整数が入力された } } </script>
上記では,
- 正規表現を使って,まず1文字ずつが数字であるか,文字列として精査する。
- 1で漏らした非整数のケースとして,先頭の"0"をカットする。カットしてから,元の文字列と等しいかどうかを見る。
という手順を踏んでいる。
javascriptの正規表現の記法については,
http://pzxa85.hp.infoseek.co.jp/www/w...
を参照のこと。
Webアプリとしての注意点
ちなみに,JavaScriptで入力値の妥当性を検証するだけでは,Webアプリケーションとして不十分である。
送信面で見た極論で言うと
つまり,ブラウザ以外の手段でhttpリクエストを生成して送信すれば,ページ上でのバリデーションをかいくぐる事ができる。フォームにはどんな値でも入れてしまえる。
この事態を避けるためには,サーバ(cgi)側で入力値の検証を行なうようにすればよい。
関連する記事:
JavaScriptの動かないコード (中級編) nullが0以上0以下と認識されてしまう
http://language-and-engineering.hatenablog.jp/entry/20090906/p1
JavaScriptの動かないコード (中級編) 文字数のカウントに失敗する
http://language-and-engineering.hatenablog.jp/entry/20120523/LengthOfUnicodeS...
JavaScriptの動かないコード (中級編) かけ算を間違える
http://language-and-engineering.hatenablog.jp/entry/20080913/1221303278