文字列が数値(float)かどうかを確認するにはどうすればよいですか?


1609

文字列がPythonで数値として表現できるかどうかを確認する最良の方法は何ですか?

私が現在持っている機能は:

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

醜くて遅いだけでなく、不格好に見えます。しかしfloat、メイン関数の呼び出しはさらに悪いため、私はより良い方法を見つけていません。


61
現在のソリューションの何が問題になっていますか?短く、速く、読みやすいです。
大佐パニック

5
また、TrueまたはFalseを返す必要はありません。代わりに適切に変更された値を返すことができます。たとえば、これを使用して、非数値を引用符で囲むことができます。
Thruston 2013年

7
変換が成功した場合は、floatの結果を返す方がよいでしょうか。あなたはまだ成功のチェックをしていて(結果はFalseです)そしてあなたはとにかく望む可能性が高い変換を実際に持っています。
Jiminion 2013

8
この質問は古いですが、これはEAFPとして文書化されているエレガントな方法だとだけ言いたかったです。したがって、おそらくこの種の問題に対する最良の解決策です。
thiruvenkadam 2013年

7
floatの結果を返さないか、失敗してもNoneを返しません。x = float('0.00'); if x: use_float(x);コードにバグがあるため、それを使用する場合。真実の値は、これらの関数Noneが最初に戻るのではなく例外を発生させる理由です。より良い解決策は、ユーティリティ関数try catchを使用せず、フロートへの呼び出しを使用したいときに囲んでおくことです。
ovangle 2016年

回答:


699

これは醜くて遅いだけでなく

私は両方に異議を唱えます。

正規表現または他の文字列解析方法は、醜くて遅いでしょう。

上記のどれよりも速くなる可能性があるかどうかはわかりません。関数を呼び出して戻ります。最も一般的な例外はスタックフレームを広範囲に検索せずにキャッチされるため、Try / Catchはそれほどオーバーヘッドをもたらしません。

問題は、数値変換関数には2種類の結果があることです。

  • 数値(数値が有効な場合)
  • ステータスコード(たとえば、errno経由)または例外。有効な数値を解析できなかったことを示します。

C(例として)はこれをいくつかの方法でハッキングします。Pythonはそれを明確かつ明示的にレイアウトします。

これを行うためのコードは完璧だと思います。


21
私はコードが完璧であるとは思わない(私はそれが非常に近いと思う):置くことがより普通であるだけに一部が「テスト」しているtry私は入れてしまうので、句return Trueelseの句try。理由の1つは、問題のコードで、確認する必要がある場合、try句の2番目のステートメントでValueErrorが発生しないことを確認する必要があることです。しかし、何も必要ないときになぜそれを使用するのですか?
Eric O Lebigot 2013

4
答えは説得力があるように見えますが、すぐに提供されないのはなぜだろうと思います...これをコピーして、どのような場合でも使用します。
セージ

9
ひどいな。数字何であるかを気にしない場合はどうですか?1行の代わりに、IsNumeric()try / catchまたはtry / catchをラップする別の行ができます。Ugh
基本的な

6
はとif is_number(s): x = float(x) else: // fail同じコード行数なので、「そのまま」では提供されませんtry: x = float(x) catch TypeError: # fail。このユーティリティ関数は、まったく不要な抽象化です。
ovangle 2016年

12
しかし、抽象化はライブラリの要点です。(任意の言語で)「isNumber」関数を使用すると、ifステートメントに直接組み込み、try-catchブロックに依存するはるかに読みやすく保守可能なコードを使用できるため、非常に役立ちます。また、コードを複数のクラス/モジュールで複数回使用する必要がある場合は、組み込み関数よりも多くのコード行を使用しています。
JamEngulfer 2016年

1612

floatの代わりに(正の符号なし)整数を解析する場合はisdigit()、文字列オブジェクトの関数を使用できます。

>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False

文字列メソッド- isdigit()Python2Python3

Unicode文字列にも何かがあります。これは、Unicodeにはあまり詳しくありません 。10進数/ 10進数です。


232
それもネガのネガです
イントレピオン

22
指数関数でも失敗: '1e3'.isdigit()-> False
ssc

35
Number!= Digitですが、文字列に整数が含まれているかどうかをテストする方法を探している人は、この質問に出くわす可能性が非常に高く、isDigitアプローチはアプリケーションに非常に適している可能性があります。
アダムパーキン

8
@AdamParkin:isdigit()int()Unicode文字のために、整数などであるかについて異なる意見を持っているがu'\u00b9'u'¹'.isdigit()あるTrueが、int(u'¹')とValueErrorを発生させます。
jfs

6
+1:isdigit()は、OPが探していたものとは異なる場合がありますが、まさに私が望んでいたものです。この回答と方法がすべてのタイプの数値をカバーしているわけではないかもしれませんが、その正確さについての議論に反して、それは依然として非常に関連があります。「数値!=数字」でも、数字は数値のサブセットです。特に、正で負ではない数値で、1から10を使用します。さらに、この方法は、文字列が数値IDであるかどうかを検査する場合に特に便利で簡単です。これは、今説明した数値のサブセットに該当することがよくあります。
ジャスティンジョンソン

161

TL; DR最適なソリューションはs.replace('.','',1).isdigit()

さまざまなアプローチを比較するいくつかのベンチマークを行いました

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

import re    
def is_number_regex(s):
    """ Returns True is string is a number. """
    if re.match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

文字列が数値でない場合、except-blockは非常に遅くなります。しかし、より重要なことに、try-exceptメソッドは、科学的表記を正しく処理する唯一のアプローチです。

funcs = [
          is_number_tryexcept, 
          is_number_regex,
          is_number_repl_isdigit
          ]

a_float = '.1234'

print('Float notation ".1234" is not supported by:')
for f in funcs:
    if not f(a_float):
        print('\t -', f.__name__)

フロート表記 ".1234"は、以下ではサポートされていません
-is_number_regex

scientific1 = '1.000000e+50'
scientific2 = '1e50'


print('Scientific notation "1.000000e+50" is not supported by:')
for f in funcs:
    if not f(scientific1):
        print('\t -', f.__name__)




print('Scientific notation "1e50" is not supported by:')
for f in funcs:
    if not f(scientific2):
        print('\t -', f.__name__)

科学的表記 "1.000000e + 50"は、以下によってサポートされていません:
-is_number_regex
-is_number_repl_isdigit
科学的表記 "1e50"は、以下によってサポートされていません:
-is_number_regex
-is_number_repl_isdigit

編集:ベンチマーク結果

import timeit

test_cases = ['1.12345', '1.12.345', 'abc12345', '12345']
times_n = {f.__name__:[] for f in funcs}

for t in test_cases:
    for f in funcs:
        f = f.__name__
        times_n[f].append(min(timeit.Timer('%s(t)' %f, 
                      'from __main__ import %s, t' %f)
                              .repeat(repeat=3, number=1000000)))

以下の機能がテストされた場所

from re import match as re_match
from re import compile as re_compile

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

def is_number_regex(s):
    """ Returns True is string is a number. """
    if re_match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


comp = re_compile("^\d+?\.\d+?$")    

def compiled_regex(s):
    """ Returns True is string is a number. """
    if comp.match(s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

ここに画像の説明を入力してください


15
素敵なチャートのために+1。私はベンチマークとグラフを見ました、すべてのTL; DRの事は明確で直感的になりました。
jcchuks 2016年

@JCChuksに同意します。このグラフは、すべてのTL; DRをすばやく取得するのに役立ちます。しかし、TL; DR(例:TL; DR:最良の解決策は s.replace('.','',1).isdigit())がこのアンサーの最初に現れるはずだと思います。いずれにせよ、それは受け入れられたものであるべきです。ありがとう!
Simon C.

10
このメソッドは負の数(ダッシュ)を処理しません。私はfloatメソッドを使用することをお勧めします。これは、間違いが起こりにくく、常に機能するためです。
Urchin

3
注意すべき重要な点は、ダッシュがあり得ないという仮定でさえ、replace-isdigitメソッドは非数(False結果)に対してのみ高速であるのに対し、try-exceptメソッドは数値(True結果)に対して高速であることです。入力のほとんどが有効な入力である場合は、try-exceptソリューションを使用することをお勧めします。
Markus von Broady

1
'1.5e-9'またはネガのような指数表記では機能しません。
EL_DON 2019年

68

考慮すべき例外が1つあります。文字列「NaN」です。

is_numberが「NaN」に対してFALSEを返すようにしたい場合、Pythonはそれを数値ではない数値の表現に変換するため、このコードは機能しません(アイデンティティの問題について話します)。

>>> float('NaN')
nan

それ以外の場合は、私が現在広範囲に使用しているコードの一部に実際に感謝する必要があります。:)

G.


2
実際、渡されたテキストが実際に数値を表していない場合は、NaN(ではなくFalse)を返すのに適した値になる可能性があります。それをチェックするのはちょっと面倒です(Pythonのfloat型は本当にそのためのメソッドが必要です)が、エラーを生成せずに計算で使用でき、結果をチェックするだけで済みます。
キンドル

7
別の例外は文字列'inf'です。どちらかinfあるいはNaNまた、Aで始まることができる+-、まだ受け入れられ。
agf

4
NaNとInfに対してFalseを返す場合は、行をx = float(s);に変更します。(x == x)および(x-1!= x)を返します。これは、InfとNaNを除くすべての浮動小数点に対してTrueを返すはずです
RyanN 2013年

5
x-1 == xより小さいfloatはtrueですinf。Python 3.2以降math.isfiniteでは、NaNでも無限でもない数値をテストしたり、その両方math.isnanとそのmath.isinf前にチェックしたりできます。
スティーブジェソップ

56

これはどう:

'3.14'.replace('.','',1).isdigit()

'。'が1つあるか、ない場合にのみtrueを返します。数字列内。

'3.14.5'.replace('.','',1).isdigit()

falseを返します

編集:別のコメントを見ただけです... .replace(badstuff,'',maxnum_badstuff)他のケースにを追加することができます。任意の調味料ではなくソルトを渡す場合(参照:xkcd#974)、これはうまくいきます:P


7
ただし、これは負の数を考慮していません。
Michael Barton

5
または、次のような指数を持つ数値1.234e56(これは、と記述されている場合があり、+1.234E+56さらにいくつかの変種もあります)。
Alfe

re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')数を決定するより良い仕事をする必要があります(すべてではありませんが、私はそれを主張していません)。これを使用することはお勧めしません。質問者の元のコードを使用する方がはるかに良いです。
Baldrickk 2017

あなたはこのソリューションのようにいけない場合、読み、これを downvoting前に!
aloisdgがcodidact.comに移動

これは、このWebサイトで今まで見た中で最もスマートなソリューションです。
Karam Qusai

41

醜くて遅いだけでなく、不格好に見えます。

慣れるまでに少し時間がかかるかもしれませんが、これはPythonのやり方です。すでに指摘したように、代替案はさらに悪いものです。ただし、この方法で処理を行うことには、ポリモーフィズムというもう1つの利点があります。

アヒルのタイピングの背後にある中心的なアイデアは、「歩いてアヒルのように話すなら、それはアヒルだ」ということです。何かを浮動小数点数に変換できるかどうかを判断する方法を変更できるように文字列をサブクラス化する必要があると判断した場合はどうなるでしょうか。または、他のオブジェクトを完全にテストする場合はどうでしょうか?上記のコードを変更せずに、これらのことを実行できます。

他の言語は、インターフェースを使用してこれらの問題を解決します。別のスレッドに適したソリューションの分析を保存します。ただし、要点は、Pythonは明らかに方程式のダックタイピング側にあり、Pythonで多くのプログラミングを行う予定がある場合は、おそらくこのような構文に慣れる必要があります(ただし、これはもちろんそれを好きでなければなりません)。

もう1つ考慮に入れたいことがあります。Pythonは、他の多くの言語と比較して、例外のスローとキャッチが非常に高速です(たとえば、.Netより30倍高速です)。なんと言っても、言語自体が例外をスローして、例外のない通常のプログラム条件(forループを使用するたびに)を伝えます。したがって、重大な問題に気付くまでは、このコードのパフォーマンスの側面についてはあまり心配しません。


1
Pythonが基本的な関数の例外を使用するもう1つの一般的な場所は、hasattr()getattr()ラップされた呼び出しtry/exceptです。それでも、例外処理は通常のフロー制御よりも遅いため、ほとんどの場合当てはまるものに例外処理を使用すると、パフォーマンスが低下する可能性があります。
キンドル

ワンライナーが必要な場合は、SOLであると思われます
基本

また、pythonicは、安価な例外があることの影響に関して、「許可よりも許しを求める方が良い」という考えです。
ヘルトンバイカー

40

Alfeが指摘した後に更新されました。複雑なハンドルは両方を扱うため、フロートを個別にチェックする必要はありません。

def is_number(s):
    try:
        complex(s) # for int, long, float and complex
    except ValueError:
        return False

    return True

以前に述べた:floatで表すことができない複素数(1 + 2iなど)を確認する必要がある場合もあります。

def is_number(s):
    try:
        float(s) # for int, long and float
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False

    return True

14
同意しません。これは通常の使用ではほとんどありません。0.0001%の誤動作の可能性のために追加の操作で呼び出しに負担をかけるのではなく、それらを使用しているときにis_complex_number()呼び出しを作成する方が良いでしょう。
Jiminion 2013

3
float()ものを完全に取り除き、complex()呼び出しが成功するかどうかを確認するだけです。によって解析されるすべてのものfloat()は、によって解析できますcomplex()
Alfe

この関数は、PandasのNaNおよびInf値を数値として返します。
fixxxer 2016年

complex('(01989)')戻り(1989+0j)ます。しかしfloat('(01989)')失敗します。だから私は使うのcomplexは良い考えではないと思います。
2018

26

以下のためにintこれを使用します。

>>> "1221323".isdigit()
True

しかし、float私たちはいくつかのトリックが必要です;-)。すべての浮動小数点数には1つのポイントがあります...

>>> "12.34".isdigit()
False
>>> "12.34".replace('.','',1).isdigit()
True
>>> "12.3.4".replace('.','',1).isdigit()
False

また、負の数の場合は次のように追加しlstrip()ます。

>>> '-12'.lstrip('-')
'12'

そして今、私たちは普遍的な方法を手に入れました:

>>> '-12.34'.lstrip('-').replace('.','',1).isdigit()
True
>>> '.-234'.lstrip('-').replace('.','',1).isdigit()
False

2
のようなものを処理しません1.234e56。また、それ99999999999999999999e99999999999999999999が数値ではないことがどのようにわかるかについても興味があります。解析しようとすると、すぐにわかります。
Alfe

これは、50mの文字列のリストでは受け入れ済みのソリューションよりも30%速く、5kの文字列のリストでは150%速く実行されます。👏–
Zev Averbach、

15

ちょうどC#を模倣する

C#には、スカラー値の解析を処理する2つの異なる関数があります。

  • Float.Parse()
  • Float.TryParse()

float.parse():

def parse(string):
    try:
        return float(string)
    except Exception:
        throw TypeError

注:例外をTypeErrorに変更した理由がわからない場合は、こちらのドキュメントをご覧ください

float.try_parse():

def try_parse(string, fail=None):
    try:
        return float(string)
    except Exception:
        return fail;

注:ブール型の「False」を返す必要はありません。これはまだ値の型だからです。失敗を示すため、どれも優れていません。もちろん、別のものが必要な場合は、failパラメータを好きなように変更できます。

floatを拡張して「parse()」と「try_parse()」を含めるには、これらのメソッドを追加するために「float」クラスをモンキーパッチする必要があります。

既存の機能を尊重したい場合、コードは次のようになります。

def monkey_patch():
    if(!hasattr(float, 'parse')):
        float.parse = parse
    if(!hasattr(float, 'try_parse')):
        float.try_parse = try_parse

サイドノート:私は個人的にはこれをモンキーパンチングと呼ぶ方が好きです。なぜなら、これを行うと言語を乱用しているように感じるのですが、YMMVです。

使用法:

float.parse('giggity') // throws TypeException
float.parse('54.3') // returns the scalar value 54.3
float.tryParse('twank') // returns None
float.tryParse('32.2') // returns the scalar value 32.2

そして、偉大な賢者パイソンは聖座シャーピサスに言った、「あなたができることなら何でも、私はもっと上手くできる。私はあなたよりももっと上手くできる」。


私は最近ほとんどJSでコーディングしていて、実際にこれをテストしなかったので、いくつかのマイナーなエラーがあるかもしれません。間違いがあったら、遠慮なく私の間違いを訂正してください。
エヴァンプレイス

複素数のサポートを追加するには、@ Matthew Wilcoxsonの回答を参照してください。stackoverflow.com/a/3335060/290340
エヴァンプレイス

1
!代わりにを使用するnotと、小さなエラーになる可能性がありますがfloat、CPythonの組み込みに属性を割り当てることはできません。
BlackJack

15

非数値の文字列の場合、 try: except:実際には正規表現よりも遅くなります。有効な数値の文字列の場合、正規表現は遅くなります。したがって、適切な方法は入力に依存します。

あなたはパフォーマンス苦境にあることが判明した場合は、新しいサードパーティのモジュールに呼ばれる使用することができますfastnumbersと呼ばれる機能を提供isfloatを。完全な開示、私は著者です。その結果を以下のタイミングに含めました。


from __future__ import print_function
import timeit

prep_base = '''\
x = 'invalid'
y = '5402'
z = '4.754e3'
'''

prep_try_method = '''\
def is_number_try(val):
    try:
        float(val)
        return True
    except ValueError:
        return False

'''

prep_re_method = '''\
import re
float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match
def is_number_re(val):
    return bool(float_match(val))

'''

fn_method = '''\
from fastnumbers import isfloat

'''

print('Try with non-number strings', timeit.timeit('is_number_try(x)',
    prep_base + prep_try_method), 'seconds')
print('Try with integer strings', timeit.timeit('is_number_try(y)',
    prep_base + prep_try_method), 'seconds')
print('Try with float strings', timeit.timeit('is_number_try(z)',
    prep_base + prep_try_method), 'seconds')
print()
print('Regex with non-number strings', timeit.timeit('is_number_re(x)',
    prep_base + prep_re_method), 'seconds')
print('Regex with integer strings', timeit.timeit('is_number_re(y)',
    prep_base + prep_re_method), 'seconds')
print('Regex with float strings', timeit.timeit('is_number_re(z)',
    prep_base + prep_re_method), 'seconds')
print()
print('fastnumbers with non-number strings', timeit.timeit('isfloat(x)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with integer strings', timeit.timeit('isfloat(y)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with float strings', timeit.timeit('isfloat(z)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print()

Try with non-number strings 2.39108395576 seconds
Try with integer strings 0.375686168671 seconds
Try with float strings 0.369210958481 seconds

Regex with non-number strings 0.748660802841 seconds
Regex with integer strings 1.02021503448 seconds
Regex with float strings 1.08564686775 seconds

fastnumbers with non-number strings 0.174362897873 seconds
fastnumbers with integer strings 0.179651021957 seconds
fastnumbers with float strings 0.20222902298 seconds

ご覧のように

  • try: except: 数値入力では高速でしたが、無効な入力では非常に低速でした
  • 入力が無効な場合、正規表現は非常に効率的です
  • fastnumbers どちらの場合も勝利

私は修正された状態です:-}こうしているようには見えませんでした。prep_code_basisとのような名前を使用prep_code_re_methodすることで、私の間違いを防ぐことができたでしょう。
Alfe

少なくともisfloat関数について、モジュールがどのように機能するか説明していただけませんか?
ソロモンウッコ2016年

@SolomonUcko文字列チェックパーツのソースコードへのリンクは次のとおりです:github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/…。基本的には、文字列内の各文字を順番にたどり、有効なフロートのパターンに従っていることを検証します。入力がすでに数値の場合は、高速なPyFloat_Checkを使用するだけです
SethMMorton 2016

1
このスレッドの最良の代替案に対してテストされた私はこのソリューションが断然最速であることを確認しました。2番目に速い方法はstr(s).strip('-').replace('.','',1).isdigit()、約10倍遅いことです。
Alexander McFarlane

14

私はこれが特に古いことを知っていますが、これを見つけた人にとって非常に貴重になる可能性のある最高投票数の回答から欠落している情報をカバーしていると思う回答を追加します。

次の各メソッドについて、入力を受け入れる必要がある場合は、それらをカウントで接続します。(0-255などではなく、整数のボーカル定義を使用していると仮定します。)

x.isdigit() xが整数かどうかをチェックするのに適しています。

x.replace('-','').isdigit() xが負かどうかをチェックするのに適しています(チェック-最初の位置)

x.replace('.','').isdigit() xが10進数かどうかをチェックするのに適しています。

x.replace(':','').isdigit() xが比率かどうかをチェックするのに適しています。

x.replace('/','',1).isdigit() xが分数かどうかをチェックするのに適しています。


1
分数の場合でも、おそらく行う必要がありx.replace('/','',1).isdigit()ます。そうしないと、2017年4月7日などの日付が数値として誤って解釈されます。
Yuxuan Chen 2017

条件を連鎖させる最良の方法については、stackoverflow.com
Daniel Braun

13

この回答は、文字列を検索するための例を含む機能を持つステップバイステップガイドを提供します。

  • 正の整数
  • 正/負-整数/浮動小数点
  • 数字をチェックするときに「NaN」(数字ではない)文字列を破棄する方法は?

文字列が 正の整数

あなたはstr.isdigit()与えられた文字列が正の整数。

結果の例:

# For digit
>>> '1'.isdigit()
True
>>> '1'.isalpha()
False

文字列が正/負-整数/浮動小数点かどうかを確認します

str.isdigit()False文字列が負の数か浮動小数かどうかを返します。例えば:

# returns `False` for float
>>> '123.3'.isdigit()
False
# returns `False` for negative number
>>> '-123'.isdigit()
False

あなたがしたい場合ものチェック負のと整数float、そしてあなたにそれをチェックするためにカスタム関数を作成することがあります。

def is_number(n):
    try:
        float(n)   # Type-casting the string to `float`.
                   # If string is not a valid `float`, 
                   # it'll raise `ValueError` exception
    except ValueError:
        return False
    return True

サンプル実行:

>>> is_number('123')    # positive integer number
True

>>> is_number('123.4')  # positive float number
True

>>> is_number('-123')   # negative integer number
True

>>> is_number('-123.4') # negative `float` number
True

>>> is_number('abc')    # `False` for "some random" string
False

数値のチェック中に「NaN」(数値ではない)文字列を破棄する

上記の関数はTrue、「NAN」(数値ではない)文字列を返します。これは、Pythonでは数値ではないことを表す有効な浮動小数点数であるためです。例えば:

>>> is_number('NaN')
True

数値が「NaN」かどうかを確認するには、次のように使用できますmath.isnan()

>>> import math
>>> nan_num = float('nan')

>>> math.isnan(nan_num)
True

または、これを確認するために追加のライブラリをインポートしたくない場合は、を使用してそれをそれ自体と比較することで単に確認できます==。PythonはFalsenanfloatがそれ自体と比較されると戻ります。例えば:

# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False

したがって、上記の機能は、is_number返すように更新することができますFalseのため"NaN"のように:

def is_number(n):
    is_number = True
    try:
        num = float(n)
        # check for "nan" floats
        is_number = num == num   # or use `math.isnan(num)`
    except ValueError:
        is_number = False
    return is_number

サンプル実行:

>>> is_number('Nan')   # not a number "Nan" string
False

>>> is_number('nan')   # not a number string "nan" with all lower cased
False

>>> is_number('123')   # positive integer
True

>>> is_number('-123')  # negative integer
True

>>> is_number('-1.12') # negative `float`
True

>>> is_number('abc')   # "some random" string
False

PS:番号のタイプに応じた各チェックの各操作には、追加のオーバーヘッドが伴います。is_number要件に合った関数のバージョンを選択してください。


12

floatへのキャストとValueErrorのキャッチは、おそらく最速の方法です。float()はそれだけを目的としているためです。文字列の解析を必要とするその他すべて(正規表現など)は、この操作用に調整されていないため、遅くなる可能性があります。私の0.02ドル。


11
「2e-2」ドルも浮動小数点数です(浮動小数点数を使用するための追加の引数:)
tzot

8
@tzotは、浮動小数点を使用して金額を表すことはできません。
ルーク、

6
@ルーク:私はあなたに完全に同意します。通貨の値浮動小数点数として表現できると私は言っただけです:)
tzot

11

あなたはUnicode文字列を使うことができます、彼らはあなたが望むだけをする方法を持っています:

>>> s = u"345"
>>> s.isnumeric()
True

または:

>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True

http://www.tutorialspoint.com/python/string_isnumeric.htm

http://docs.python.org/2/howto/unicode.html


2
負でない整数の場合は
問題ありません

1
s.isdecimal()s文字列が負でない整数かどうかをチェックします。拒否するs.isnumeric()文字が含まれていint()ます。
jfs 2014年

9

私はどの方法が最も速いかを見たかった。全体として、check_replace関数によって最良かつ最も一貫した結果が得られました。check_exception関数によって最も速い結果が得られましたが、例外が発生しなかった場合に限ります。つまり、そのコードが最も効率的ですが、例外をスローするオーバーヘッドは非常に大きくなります。

キャストが成功したかどうかを確認することが正確な唯一の方法であることに注意してください。たとえば、これは check_exceptionが、他の2つのテスト関数は、有効なフロートに対してFalseを返します。

huge_number = float('1e+100')

ベンチマークコードは次のとおりです。

import time, re, random, string

ITERATIONS = 10000000

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self
    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

def check_regexp(x):
    return re.compile("^\d*\.?\d*$").match(x) is not None

def check_replace(x):
    return x.replace('.','',1).isdigit()

def check_exception(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

to_check = [check_regexp, check_replace, check_exception]

print('preparing data...')
good_numbers = [
    str(random.random() / random.random()) 
    for x in range(ITERATIONS)]

bad_numbers = ['.' + x for x in good_numbers]

strings = [
    ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randint(1,10)))
    for x in range(ITERATIONS)]

print('running test...')
for func in to_check:
    with Timer() as t:
        for x in good_numbers:
            res = func(x)
    print('%s with good floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in bad_numbers:
            res = func(x)
    print('%s with bad floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in strings:
            res = func(x)
    print('%s with strings: %s' % (func.__name__, t.interval))

2017 MacBook Pro 13でPython 2.7.10を実行した結果は次のとおりです。

check_regexp with good floats: 12.688639
check_regexp with bad floats: 11.624862
check_regexp with strings: 11.349414
check_replace with good floats: 4.419841
check_replace with bad floats: 4.294909
check_replace with strings: 4.086358
check_exception with good floats: 3.276668
check_exception with bad floats: 13.843092
check_exception with strings: 15.786169

2017 MacBook Pro 13でPython 3.6.5を実行した結果は次のとおりです。

check_regexp with good floats: 13.472906000000009
check_regexp with bad floats: 12.977665000000016
check_regexp with strings: 12.417542999999995
check_replace with good floats: 6.011045999999993
check_replace with bad floats: 4.849356
check_replace with strings: 4.282754000000011
check_exception with good floats: 6.039081999999979
check_exception with bad floats: 9.322753000000006
check_exception with strings: 9.952595000000002

以下は、2017 MacBook Pro 13でのPyPy 2.7.13の結果です。

check_regexp with good floats: 2.693217
check_regexp with bad floats: 2.744819
check_regexp with strings: 2.532414
check_replace with good floats: 0.604367
check_replace with bad floats: 0.538169
check_replace with strings: 0.598664
check_exception with good floats: 1.944103
check_exception with bad floats: 2.449182
check_exception with strings: 2.200056

10
無効なケースのパフォーマンスもテストする必要があります。これらの数値で例外は発生しません。これはまさに「遅い」部分です。
UgoMéda2013年

1
@UgoMéda私は2013年からあなたのアドバイスを取り入れてそれを行いました:)
Ron Reiter

「キャストの成功を確認することが正確な唯一の方法であることに注意してください」<-これは実際には真実ではありません。上記の私の答えの正規表現を使用してテストを実行しましたが、実際には正規表現よりも高速に実行されます。上記の回答に結果を追加します。
David Ljung Madison Stellar

ちなみに、おかしな点として、悪い数字の作成者は実際にはいくつかの正当な数字を作成できますが、それは非常にまれです。:)
David Ljung Madison Stellar

8

したがって、すべてをまとめて、ナン、無限大、複素数(iではなくjで指定されているように見える、つまり1 + 2j)をチェックすると、次のようになります。

def is_number(s):
    try:
        n=str(float(s))
        if n == "nan" or n=="inf" or n=="-inf" : return False
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False
    return True

これまでのところ、最良の答えです。ありがとう
1

6

入力は次のようになります。

a="50" b=50 c=50.1 d="50.1"


1-一般的な入力:

この関数の入力はすべてにできます!

指定された変数が数値かどうかを調べます。数値文字列は、オプションの符号、任意の桁数、オプションの小数部およびオプションの指数部で構成されます。したがって、+ 0123.45e6は有効な数値です。16進(例:0xf4c3b00c)および2進(例:0b10100111001)表記は許可されていません。

is_numeric関数

import ast
import numbers              
def is_numeric(obj):
    if isinstance(obj, numbers.Number):
        return True
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            #if used + or - in digit :
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

テスト:

>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True

is_float関数

指定された変数がfloatかどうかを調べます。float文字列は、オプションの符号、任意の桁数、...で構成されます

import ast

def is_float(obj):
    if isinstance(obj, float):
        return True
    if isinstance(obj, int):
        return False
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        if not isinstance(nodes[-1].n, float):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

テスト:

>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True

astとは何ですか?


2-変数の内容が 文字列であると

str.isdigit()メソッドを使用する

>>> a=454
>>> a.isdigit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'isdigit'
>>> a="454"
>>> a.isdigit()
True

3数値入力:

int値を検出します。

>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>> 

フロートを検出:

>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True

ast」とは

4

スピードテストをしました。文字列がおそらく数であることを除いて/試し戦略が文字列の最速possible.Ifありそうにない数であるように、あなたが興味を持っている整数のチェック、それはいくつかのテスト(isdigitプラス見出しを行うにworths 「-」)。浮動小数点数を確認したい場合は、try / except code whitoutエスケープを使用する必要があります。


4

文字列が基本型(float、int、str、bool)にキャストされるかどうかを判断する必要がありました。インターネットで何も見つからなかった後、私はこれを作成しました:

def str_to_type (s):
    """ Get possible cast type for a string

    Parameters
    ----------
    s : string

    Returns
    -------
    float,int,str,bool : type
        Depending on what it can be cast to

    """    
    try:                
        f = float(s)        
        if "." not in s:
            return int
        return float
    except ValueError:
        value = s.upper()
        if value == "TRUE" or value == "FALSE":
            return bool
        return type(s)

str_to_type("true") # bool
str_to_type("6.0") # float
str_to_type("6") # int
str_to_type("6abc") # str
str_to_type(u"6abc") # unicode       

タイプをキャプチャして使用できます

s = "6.0"
type_ = str_to_type(s) # float
f = type_(s) 

3

ライアンは示唆している

NaNとInfに対してFalseを返す場合は、行をx = float(s);に変更します。(x == x)および(x-1!= x)を返します。これは、InfとNaNを除くすべての浮動小数点に対してTrueを返す必要があります

しかし、十分に大きなフロートの場合x-1 == xはtrueを返すため、これはうまく機能しません。例えば、2.0**54 - 1 == 2.0**54


3

私はあなたの解決策は素晴らしいと思います、正しい正規表現の実装があります。

これらの回答に対する正規表現に対する多くの嫌悪感は正当化されないと思われますが、正規表現は適度にクリーンで正確かつ高速である可能性があります。それは本当にあなたが何をしようとしているのかに依存します。元の質問は、(タイトルに従って)「文字列が数値(float)として表現できるかどうかを確認する」方法でした。おそらく、数値/浮動小数点値が有効であることを確認したら、数値/浮動小数点値を使用することになるでしょう。その場合、try / exceptは非常に有効です。しかし、何らかの理由で、文字列数値であるその後、正規表現も正常に動作しますが、正しく取得することは困難です。これまでの正規表現の答えのほとんどは、たとえば、Pythonに関する限り、浮動小数点数である整数部分( ".7"など)がない文字列を適切に解析しないと思います。また、小数部分が不要な単一の正規表現で確認するのは少し難しいです。これを示すために2つの正規表現を含めました。

それは「数」が何であるかに関して興味深い質問を引き起こします。Pythonのフロートとして有効な「inf」を含めますか?または、「数値」であるがpythonでは表現できない数値を含めるか(float maxよりも大きい数値など)。

また、数値の解析方法にはあいまいさもあります。たとえば、「-20」はどうですか?これは「番号」ですか?これは「20」を表す法的な方法ですか?Pythonは "var = --20"を実行して20に設定します(実際にはこれは式として扱われるためです)が、float( "-20")は機能しません。

とにかく、詳細情報がない場合、Pythonがそれらを解析するときにすべてのintとfloat カバーすると私が信じている正規表現は次のとおりです。

# Doesn't properly handle floats missing the integer part, such as ".7"
SIMPLE_FLOAT_REGEXP = re.compile(r'^[-+]?[0-9]+\.?[0-9]+([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           mantissa (34)
                            #                    exponent (E+56)

# Should handle all floats
FLOAT_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           OR
                            #             int/mantissa (12.34)
                            #                            exponent (E+56)

def is_float(str):
  return True if FLOAT_REGEXP.match(str) else False

テスト値の例:

True  <- +42
True  <- +42.42
False <- +42.42.22
True  <- +42.42e22
True  <- +42.42E-22
False <- +42.42e-22.8
True  <- .42
False <- 42nope

@ ron-reiterの回答でベンチマークコードを実行すると、この正規表現は実際には通常の正規表現よりも高速で、例外よりも悪い値の処理がはるかに高速であることがわかります。結果:

check_regexp with good floats: 18.001921
check_regexp with bad floats: 17.861423
check_regexp with strings: 17.558862
check_correct_regexp with good floats: 11.04428
check_correct_regexp with bad floats: 8.71211
check_correct_regexp with strings: 8.144161
check_replace with good floats: 6.020597
check_replace with bad floats: 5.343049
check_replace with strings: 5.091642
check_exception with good floats: 5.201605
check_exception with bad floats: 23.921864
check_exception with strings: 23.755481

それが正しいことを願って-反例について聞いてみたいです。:)
David Ljung Madison Stellar

2
import re
def is_number(num):
    pattern = re.compile(r'^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$')
    result = pattern.match(num)
    if result:
        return True
    else:
        return False


​>>>: is_number('1')
True

>>>: is_number('111')
True

>>>: is_number('11.1')
True

>>>: is_number('-11.1')
True

>>>: is_number('inf')
False

>>>: is_number('-inf')
False

2
1e6数を表すことを考えていませんか?
マークディキンソン

1

これが私の簡単な方法です。いくつかの文字列をループ処理していて、それらが数値であることが判明した場合は、それらを配列に追加するとします。

try:
    myvar.append( float(string_to_check) )
except:
    continue

myvar.apppendを、文字列であることが判明した場合は、文字列で実行する任意の操作に置き換えます。アイデアは、float()操作を使用して、返されたエラーを使用して、文字列が数値かどうかを判断することです。


配列に問題がある場合に誤って例外がトリガーされるのを防ぐために、その関数の追加部分をelseステートメントに移動する必要があります。
DarwinSurvivor 2013

1

あなたが言及した関数も使用しましたが、すぐに文字列が「Nan」、「Inf」、およびそのバリエーションが数値と見なされることに気付きました。したがって、これらのタイプの入力でfalseを返し、「1e3」バリアントに失敗しない、関数の改良バージョンを提案します。

def is_float(text):
    try:
        float(text)
        # check for nan/infinity etc.
        if text.isalpha():
            return False
        return True
    except ValueError:
        return False

1

このコードは、正規表現を使用して指数、浮動小数点数、整数を処理します。

return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False

1

ユーザーヘルパー関数:

def if_ok(fn, string):
  try:
    return fn(string)
  except Exception as e:
    return None

その後

if_ok(int, my_str) or if_ok(float, my_str) or if_ok(complex, my_str)
is_number = lambda s: any([if_ok(fn, s) for fn in (int, float, complex)])

0

TrueやFalseよりも有用な値を返すことで、例外の手法を有効な方法で一般化できます。たとえば、この関数は引用符を文字列に配置しますが、数値はそのままにします。これは、Rのいくつかの変数定義を作成するための迅速で汚れたフィルターに必要なものです。

import sys

def fix_quotes(s):
    try:
        float(s)
        return s
    except ValueError:
        return '"{0}"'.format(s)

for line in sys.stdin:
    input = line.split()
    print input[0], '<- c(', ','.join(fix_quotes(c) for c in input[1:]), ')'

0

私はこのスレッドにつながった問題、つまり最も直感的な方法でデータのコレクションを文字列と数値に変換する方法に取り組んでいました。元のコードを読んだ後、必要なものが2つの点で異なることに気付きました。

1-文字列が整数を表す場合、整数の結果が必要でした

2-数値または文字列の結果をデータ構造に貼り付けたい

だから私はこの派生物を生成するために元のコードを適合させました:

def string_or_number(s):
    try:
        z = int(s)
        return z
    except ValueError:
        try:
            z = float(s)
            return z
        except ValueError:
            return s


0
def is_float(s):
    if s is None:
        return False

    if len(s) == 0:
        return False

    digits_count = 0
    dots_count = 0
    signs_count = 0

    for c in s:
        if '0' <= c <= '9':
            digits_count += 1
        elif c == '.':
            dots_count += 1
        elif c == '-' or c == '+':
            signs_count += 1
        else:
            return False

    if digits_count == 0:
        return False

    if dots_count > 1:
        return False

    if signs_count > 1:
        return False

    return True
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.