文字列の値を数値に変換する前に、それが変換できるかを調べる必要がある。例外を使ってこれを調べる方法と正規表現を使う方法の2つを紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
# 文字列が数値を表し、int/float関数による変換が可能かどうかを判定
def isint(s): # 整数値を表しているかどうかを判定
try:
int(s, 10) # 文字列を実際にint関数で変換してみる
except ValueError:
return False
else:
return True
def isfloat(s): # 浮動小数点数値を表しているかどうかを判定
try:
float(s) # 文字列を実際にfloat関数で変換してみる
except ValueError:
return False
else:
return True
s1 = '123'
s2 = '123b'
r1 = isint(s1)
r2 = isint(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 123: True, 123b: False
s1 = '1.23e-1'
s2 = '1.23e'
r1 = isfloat(s1)
r2 = isfloat(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 1.23e-1: True, 1.23e: False
# 正規表現を使う
import re
def isint2(s): # 正規表現を使って判定を行う
p = '[-+]?\d+'
return True if re.fullmatch(p, s) else False
def isfloat2(s): # 正規表現を使って判定を行う
p = '[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?'
return True if re.fullmatch(p, s) else False
s1 = '123'
s2 = '123b'
r1 = isint2(s1)
r2 = isint2(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 123: True, 123b: False
s1 = '1.23e-1'
s2 = '1.23e'
r1 = isfloat2(s1)
r2 = isfloat2(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 1.23e-1: True, 1.23e: False
input関数で入力された文字列を数値に変換するなど、文字列を数値に変換しなければならないことはよくある。ただし、その際には文字列が数値に変換可能かどうかを前もって調べる必要もある。
文字列を数値に変換可能かどうかを調べるには、実際にint関数やfloat関数にその文字列を渡してみるのが簡単だ。例外が発生すれば変換できず、そうでなければ変換できる。このことを利用して、次のようにisint関数やisfloat関数を定義できるだろう。
def isint(s): # 整数値を表しているかどうかを判定
try:
int(s, 10) # 文字列を実際にint関数で変換してみる
except ValueError:
return False # 例外が発生=変換できないのでFalseを返す
else:
return True # 変換できたのでTrueを返す
def isfloat(s): # 浮動小数点数値を表しているかどうかを判定
try:
float(s) # 文字列を実際にfloat関数で変換してみる
except ValueError:
return False # 例外が発生=変換できないのでFalseを返す
else:
return True # 変換できたのでTrueを返す
使用例を以下に示す。
s1 = '123'
s2 = '123b'
r1 = isint(s1)
r2 = isint(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 123: True, 123b: False
s1 = '1.23e-1'
s2 = '1.23e'
r1 = isfloat(s1)
r2 = isfloat(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # 1.23e-1: True, 1.23e: False
Pythonでは全角の10進数字などでも数値への変換が可能なことは覚えておこう。以下に例を示す。ただし、符号(+/−)や小数点、指数表記のe/Eなどは半角でなければならない。
s = '123' # 全角の10進数字でも変換可能
result = isint(s)
print(result) # True
s = '+123' # 符号が全角だと変換できない
result = isint(s)
print(result) # False
半角の数字だけであるかまでを考慮に入れたいのであれば、以下の正規表現を使う方法を使う必要がある。
正規表現を使って、次のような関数を定義してもよい。
import re
def isint2(s): # 正規表現を使って判定を行う
p = '[-+]?\d+'
return True if re.fullmatch(p, s) else False
def isfloat2(s): # 正規表現を使って判定を行う
p = '[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?'
return True if re.fullmatch(p, s) else False
isint2関数は「0個か1個符号」に続けて「1個以上の10進数字」が並ぶパターンが文字列全体にマッチするかどうかを調べている。
isfloat2関数は「0個か1個の符号」の後に、「1個以上の10進数字」「0個か1個の小数点(.)」「0個以上の10進数字」という文字の並びあるいは「小数点(.)」「1個以上の10進数字」が続き、最後に「指数表記を表すeかE」「0個が1個の符号」「1個以上の10進数字」というパターンが、文字列全体にマッチするかどうかを調べている。
Pythonでは「1.23」「-1.」「1.e-2」など、さまざまな形で浮動小数点数値を表せる。例えば、「-1.」は「1個の符号の後に、1個の10進数字、1個の小数点、0個の10進数字」であり上記パターンにマッチする。また、「.1e1」は「0個の符号の後に、小数点、1個の10進数字、指数表記を示すe、0個の符号、1個の10進数字」であり、こちらも上記のパターンにマッチする。
これらのパターンをなるべく網羅したつもりだが、漏れているものや実際には浮動小数点数値に変換できないものがあるかもしれないので、上記のコードをそのまま使う場合にはテストを欠かさずに行ってほしい。
以下に使用例を示す。
s1 = '-123'
s2 = '123b'
r1 = isint2(s1)
r2 = isint2(s2)
print(f'{s1}: {r1}, {s2}: {r2}') # -123: True, 123b: False
s_list = ['1.23', '-1.', '1.e-2', '1.23e']
result = {s: isfloat(s) for s in s_list} # isfloat関数で判定
result2 = {s: isfloat2(s) for s in s_list} # isfloat2関数で判定
print(result) # {'1.23': True, '-1.': True, '1.e-2': True, '1.23e': False}
print(result2) # {'1.23': True, '-1.': True, '1.e-2': True, '1.23e': False}
上記コードで使用している正規表現中の文字クラス「\d」は、Unicodeで10進数字としての属性が与えられているもの(General_Categoryプロパティの値がNdのもの)を表す。よって、正規表現を使っていないコードと同様に全角の10進数字なども変換可能と判定する。半角の10進数値のみを考慮の対象としたいのであれば、fullmatch関数の第3引数でre.ASCIIフラグを指定すること。
以下に例を示す。
def isint3(s, flags=0):
p = '[-+]?\d+'
return True if re.fullmatch(p, s, flags) else False
s = '123'
r1 = isint3(s)
r2 = isint3(s, re.ASCII)
print(f'without re.ASCII: {r1}, with re.ASCII: {r2}')
# 出力結果:
# without re.ASCII: True, with re.ASCII: False
ここではフラグを受け取るパラメーターを持つisint3関数を定義して、受け取ったフラグの値をre.fullmatch関数の第3引数に渡すようにした。re.ASCII値を与えることで動作が変わっていることを確認してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.