文字列がfloat型に変換可能かどうかを確認する正規表現について訂正と補足
以前、ある文字列がfloat型に変換可能かどうかを確認する方法を扱った以下の2つの記事を書きました。
これらの記事、特に後者について訂正と補足をしたいと思います。
1年以上前の記事なので今さら訂正、補足をするのはきまりが悪いのですが明らかなミスがありましたので。
2つ目の記事の中で、ある文字列がfloat型に変換可能かどうかを判別する正規表現として
re.compile("^\d+(\.\d+)?\Z")
というのを書いていますが、これだと負の値がマッチしないというミスがありました。
num_reg = re.compile("^\d+(\.\d+)?\Z") print bool(num_reg.match('-14.1')) # False
また'15e-3'というようなeを用いたべき乗表現にも対応できていませんでした。(これについてはただ単に知りませんでした・・・)
実際にはこれもfloat型に変換可能です。
print float('15e-3') # 0.015
次にこれはミスではありませんが前述の記事では「ある文字列がfloat型に変換可能かどうかを判別する正規表現」と言いながら、同じ記事内で「'50.'のような文字列はfloat型に変換できるが算数的に正しくないのでマッチしないように書く」というちぐはぐなことをしていたので'50.'や'.3'など算数的には正しくないがfloat()関数でfloat型に変換可能であればマッチするようにすべきだったと考えています。
以上を踏まえ、より正確なfloat()関数でfloat型に変換可能かどうかを判定する正規表現を書いてみました。
re.compile('^[+-]?(\d*\.\d+|\d+\.?\d*)([eE][+-]?\d+|)\Z')
これにより負の値およびeによるべき乗表現にも対応できているはずです。
num_reg = re.compile('^[+-]?(\d*\.\d+|\d+\.?\d*)([eE][+-]?\d+|)\Z') print bool(num_reg.match('15e-3')) #True print bool(num_reg.match('-3.14')) #True print bool(num_reg.match('0')) #True print bool(num_reg.match('5')) #True print bool(num_reg.match('3.14')) #True print bool(num_reg.match('1250.5833')) #True print bool(num_reg.match('50.')) #True print bool(num_reg.match('3..1')) #False print bool(num_reg.match('3.1.4')) #False print bool(num_reg.match('.5')) #True print bool(num_reg.match('..5')) #False print bool(num_reg.match('abc')) #False print bool(num_reg.match('15a')) #False print bool(num_reg.match('a15')) #False print bool(num_reg.match(u'こんにちは')) #False
'(\d*\.\d+|\d+\.?\d*)'という部分が冗長に感じられるのですが'.5'や'5.'にはマッチするが'.'にはマッチしないように書くにはこれしか思い浮かびませんでした。
ところでこれを言うと元も子もないのですがfloat型に変換可能かどうかをチェックするなら正規表現を使うよりとりあえずfloat()してみて例外をチェックするほうが直感的です。
try: print float('5') except ValueError: print u'変換できない'
なので上の正規表現は実用的ではないかもしれません。
以上訂正と補足させて頂きます。