Pythonのisdigit(),isdecimal(),isnumeric()の違いを調べてみた
(2017/8/7追記) 当時は記事内容の通りだったんですが、現在のpython3.6や2.7の最新だとローマ数字はisdigitでFalseを返すようです
いつもtwitterでお世話になってる方のブログ記事でこんな記述がありました。
#91 [Python][TDD]テスト駆動開発でFizzBuzzしてみようず! « Python « a wandering wolf
str型には、次の検証用メソッドがあります。
str.isdecimal()
str.isdigit()
str.isnumeric()正直、私にはこれらの違いが分かりませんでした(´・ω・`)
Python2.7には isdigit() しかないようなのでPython3.2あたりで追加されたんでしょうか。気になったので違いを検証してみました。
検証
num = "1" # まずはunicodeで num.isdigit() # True num.isdecimal() # True num.isnumeric() # True num = "1" # 全角で渡してみる。 num.isdigit() # True num.isdecimal() # True num.isnumeric() # True num = b"1" # byteで渡してみる num.isdigit() # True num.isdecimal() # AttributeError 'bytes' object has no attribute 'isdecimal' num.isnumeric() # AttributeError 'bytes' object has no attribute 'isnumeric' num = "IV" # ローマ数字で渡してみる num.isdigit() # True num.isdecimal() # False num.isnumeric() # True num = "四" # 漢数字で渡してみる num.isdigit() # False num.isdecimal() # False num.isnumeric() # True
まとめるとこんな感じ。
isdigit() True: ユニコード文字・バイト文字・全角文字・ローマ数字 False: 漢数字 Error: なし isdecimal() True: ユニコード文字・全角文字 False: ローマ数字・漢数字 Error: バイト文字 isnumeric() True: ユニコード文字・全角・ローマ数字・漢数字 False: なし Error: バイト文字
isdigit() は主にアルファベット圏の人が数字だと思うもので、isnumeric() は漢字圏の人の為に漢数字などの英語圏では割とマイナーな数字もサポートしましたよってもの、isdecimal() はアラビア数字しか認めませんよってものという解釈に落ち着きました。
漢数字やペルシア文字などがどの程度通るか実験。
※「百」の左は「卌」です。はてダのスーパーpre記法中では文字化けしてしまうようです。
# coding:utf-8 kanji = [ "〇","零","一","壱","二","弐","三","参", "四","五","六","七","八","九","十","廿", "卅","卌","百","千","万","萬","億" ] for i in kanji: print('"{0}".isnumeric()-> {1}'.format(i, i.isnumeric())) #"〇".isnumeric()-> True #"零".isnumeric()-> True #"一".isnumeric()-> True #"壱".isnumeric()-> True #"二".isnumeric()-> True #"弐".isnumeric()-> True #"三".isnumeric()-> True #"参".isnumeric()-> True #"四".isnumeric()-> True #"五".isnumeric()-> True #"六".isnumeric()-> True #"七".isnumeric()-> True #"八".isnumeric()-> True #"九".isnumeric()-> True #"十".isnumeric()-> True #"廿".isnumeric()-> True #"卅".isnumeric()-> True #"卌".isnumeric()-> True #"百".isnumeric()-> True #"千".isnumeric()-> True #"万".isnumeric()-> True #"萬".isnumeric()-> True #"億".isnumeric()-> True
Windowsの場合コマンドラインで実行するとUnicodeEncodeError吐きますが、IDLEとかだとこのような結果になります。はてダがペルシア文字等を「૫」などのように変換してしまうため例には含めませんでしたが、それらもちゃんとTrueが返りました。Unicodeで定義されてる数字ならほぼ通るんじゃないでしょうか。少なくとも日本人が普段使う漢数字は問題なく通ると思います。
おまけ:unicodedata モジュール
unicodedata モジュールには文字列が数字か判定するのではなくて、文字列を数値にして返すメソッドがあります。(これはPython 2.6の時点で存在する)
http://www.python.jp/doc/release/library/unicodedata.html
unicodedata.digit("2") # 2 unicodedata.decimal("2") # 2 unicodedata.numeric("2") # 2.0 unicodedata.digit("2") # 2 unicodedata.decimal("2") # 2 unicodedata.numeric("2") # 2.0 unicodedata.digit(b"3") # TypeError: must be str, not bytes unicodedata.decimal(b"3") # TypeError: must be str, not bytes unicodedata.numeric(b"3") # TypeError: must be str, not bytes unicodedata.digit("VIII") # ValueError: not a digit unicodedata.decimal("VIII") # ValueError: not a decimal unicodedata.numeric("VIII") # 8.0 unicodedata.digit("四") # ValueError: not a digit unicodedata.decimal("四") # ValueError: not a decimal unicodedata.numeric("四") # 4.0
unicode文字を検査するメソッドなのでバイト文字列を渡したらエラーになるのは当たり前として、ここでもnumericは何でも数値として認識してくれるようなので、ユーザーが漢数字で入力してもちゃんと計算してくれるシステムとかが簡単に実装できそうです。まあどの程度が環境依存なのかがちょっと怖いですが。