isdigit()について
先日Pythonのisnan()はそもそも文字列を評価できないので文字列が数値に変換可能な形("10"とか"0.5"など)かどうかを判定できないということを書いたのですが、Pythonにはisdigit()という文字列が数字かどうかを判定する標準の関数がありました。
print "0".isdigit() #True print "abc".isdigit() #False print "a3".isdigit() #False print "500".isdigit() #True
ただし、isdigit()は文字列が数値だけかどうかを判定するので"."を含むfloat型はFalseになってしまいます。
print "0.0".isdigit() #False print "3.14".isdigit() #False
小数点を含む場合もTrueと判定できるようにする方法を考えたのですが、最も単純な方法は"."をreplaceしてしまう方法でしょうか。
print "0.0".replace(".","").isdigit() #True print "3.14".replace(".","").isdigit() #True
この方法は評価する文字列が"."を必ず一つしか含まないことが保証されている状況であれば正しく評価可能になりますがユーザーの入力を受け取る場合など、どのような文字列が入力されるか分からない状況では誤認の可能性もあります。
print "0..0".replace(".","").isdigit() #True print "3.1.4".replace(".","").isdigit() #True print "..5".replace(".","").isdigit() #True
そこで最初に現れる"."のみを置換する方法にしてみます。
print "0..0".replace(".","",1).isdigit() #False print "3.1.4".replace(".","",1).isdigit() #False print "..5".replace(".","",1).isdigit() #False print "3.14".replace(".","",1).isdigit() #True print "abc".replace(".","",1).isdigit() #False print "5".replace(".","",1).isdigit() #True
これで"."が2つ以上登場するような値に対してはFalseを返すようになりましたが、まだ先頭に1つだけ"."がついているような値にはTrueを返してしまいます。
print ".14".replace(".","",1).isdigit() #True
このような場合にもFalseを返すようにするには先頭が数字かどうかをチェックすればいいですね。ただそうなると条件が2つになるのでここまでのように1行のパターンで書くのは難しいです。
これ以上1行でやるには正規表現を使わないと無理そうです。
こちらのページで紹介されている方法を改良して正規表現を使って判定する方法を書いてみました。
import re print bool(re.compile("^\d+\.?\d*\Z").match("0")) #True print bool(re.compile("^\d+\.?\d*\Z").match("5")) #True print bool(re.compile("^\d+\.?\d*\Z").match("3.14")) #True print bool(re.compile("^\d+\.?\d*\Z").match("1250.5833")) #True print bool(re.compile("^\d+\.?\d*\Z").match("3..1")) #False print bool(re.compile("^\d+\.?\d*\Z").match("3.1.4")) #False print bool(re.compile("^\d+\.?\d*\Z").match(".5")) #False print bool(re.compile("^\d+\.?\d*\Z").match("..5")) #False print bool(re.compile("^\d+\.?\d*\Z").match("abc")) #False print bool(re.compile("^\d+\.?\d*\Z").match("15a")) #False print bool(re.compile("^\d+\.?\d*\Z").match("a15")) #False print bool(re.compile("^\d+\.?\d*\Z").match(u"こんにちは")) #False
これで数値に変換可能かどうか判定できそうです。
(2/18追記。上の正規表現の書き方には補足があります→昨日のエントリの補足+α - 主にプログラムを勉強するブログ)