PHPで数値判定をするときは"e"に気をつけよう

指数表現を理解していなかったために間違ってしまった問題があったのでメモ。

少し実装方法に触れてるのでアウトだったら消します。

paizaラーニングの問題B104:データのクレンジングで次の条件がありました。

今回行うクレンジングでは、回答が 0 以上 100 以下の整数ではないデータをすべて取り除きます。なお、先頭に 0 がついているデータ (035 など) は有効です。

上記説明を簡単にいうと、インプットの文字列が0以上100以下の整数であるかをチェックする必要があるということです。 インプット文字列は以下の条件を満たします。

  • -1,000 ≦ s_{i, j} ≦ 1,000 または、「英字小文字 / 数字」からなる文字列
  • 1 ≦ 文字列 s_{i, j} の長さ ≦ 5

このチェックを以下のように実装しました。

function hoge(string $value): bool
{
    if (!is_numeric($value))
    {
        // 数値文字列判定
        // $valueに英字が含まれている場合にfalseを返す
        return false;
    }

    $value = intval($value);
    // 0 以上 100 以下を判定
    return ($value >= 0 && $value <= 100);
}

しかし、この実装で提出するとエラーとなるパターンがありました。それが、eを含むときです。 PHPではeを指数表記として利用しています。例えば次の文字列は数値文字列として判定されます。

  • 3e1
  • 1e2

REPLを使って確認してみます。

php > echo 3e1;
30
php > echo 1e1;
10
php > var_dump(is_numeric("3e1"));
bool(true)
php > var_dump(is_numeric("1e2"));
bool(true)

そのため、整数チェックをする場合、次のうちどちらかを採用するのが良さそうです。

  • ctype_digit 関数で数値チェックをする
  • preg_match 関数を使って正規表現でチェックする