かどうかを伝えるためにどのような方法がある文字列が(例えば、整数を表し'3'
、'-17'
ではなく、'3.14'
または'asfasfas'
メカニズム以外のtry /を使用しない)は?
is_int('3.14') = False
is_int('-7') = True
かどうかを伝えるためにどのような方法がある文字列が(例えば、整数を表し'3'
、'-17'
ではなく、'3.14'
または'asfasfas'
メカニズム以外のtry /を使用しない)は?
is_int('3.14') = False
is_int('-7') = True
回答:
try/except
sをあちこちで使用することに本当にイライラしている場合は、ヘルパー関数を作成してください:
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False
Pythonが整数と見なすすべての文字列を正確にカバーするために、コードはさらに多くなるでしょう。私はこれについてただpythonicであると言います。
>>> print RepresentsInt(10.0)
True
>>> print RepresentsInt(10.06)
True
あなたが使うことができる正の整数で.isdigit
:
>>> '16'.isdigit()
True
ただし、負の整数では機能しません。次のことを試してみてください:
>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True
これは、この意味でのキャスト'16.0'
と同様の形式では機能しませんint
。
編集:
def check_int(s):
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
u'²'.isdigit()
trueですがint(u'²')
、ValueError が発生します。u.isdecimal()
代わりに使用してください。str.isdigit()
ロケールに依存するのPython 2である
check_int('')
が返される代わりに例外が発生しますFalse
ご存知のように、何らかの理由でtry / exceptがそれほどうまく機能しないことがわかりました(そしてこれを何度もテストしました)。私は頻繁にいくつかの方法を試しますが、try / exceptを使用してテストされたものの中で最高のパフォーマンスを発揮するメソッドを見つけたことはないと思います。実際、これらのメソッドは通常、最悪の場合、最悪の場合。すべての場合ではなく、多くの場合。多くの人がそれを「Pythonic」のやり方だと言っているのを知っていますが、それは私が彼らと別れる場所の1つです。私には、それは非常に高性能でもエレガントでもないので、エラーのトラップとレポートにのみ使用する傾向があります。
PHP、perl、ruby、C、さらにはおかしなシェルにも整数文字列の文字列をテストするための単純な関数があることを不満に思っていましたが、これらの仮定を検証するためのデューデリジェンスは私をつまずきました!どうやらこの欠如はよくある病気です。
これがブルーノの投稿の素早い汚い編集です。
import sys, time, re
g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
testvals = [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', '06',
# non-integers
'abc 123',
1.1, -1.1, '1.1', '-1.1', '+1.1',
'1.1.1', '1.1.0', '1.0.1', '1.0.0',
'1.0.', '1..0', '1..',
'0.0.', '0..0', '0..',
'one', object(), (1,2,3), [1,2,3], {'one':'two'},
# with spaces
' 0 ', ' 0.', ' .0','.01 '
]
def isInt_try(v):
try: i = int(v)
except: return False
return True
def isInt_str(v):
v = str(v).strip()
return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
def isInt_re(v):
import re
if not hasattr(isInt_re, 'intRegex'):
isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
return isInt_re.intRegex.match(str(v).strip()) is not None
def isInt_re2(v):
return g_intRegex.match(str(v).strip()) is not None
def check_int(s):
s = str(s)
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
def timeFunc(func, times):
t1 = time.time()
for n in range(times):
for v in testvals:
r = func(v)
t2 = time.time()
return t2 - t1
def testFuncs(funcs):
for func in funcs:
sys.stdout.write( "\t%s\t|" % func.__name__)
print()
for v in testvals:
if type(v) == type(''):
sys.stdout.write("'%s'" % v)
else:
sys.stdout.write("%s" % str(v))
for func in funcs:
sys.stdout.write( "\t\t%s\t|" % func(v))
sys.stdout.write("\r\n")
if __name__ == '__main__':
print()
print("tests..")
testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2, check_int))
print()
print("timings..")
print("isInt_try: %6.4f" % timeFunc(isInt_try, 10000))
print("isInt_str: %6.4f" % timeFunc(isInt_str, 10000))
print("isInt_re: %6.4f" % timeFunc(isInt_re, 10000))
print("isInt_re2: %6.4f" % timeFunc(isInt_re2, 10000))
print("check_int: %6.4f" % timeFunc(check_int, 10000))
パフォーマンスの比較結果は次のとおりです。
timings..
isInt_try: 0.6426
isInt_str: 0.7382
isInt_re: 1.1156
isInt_re2: 0.5344
check_int: 0.3452
ACメソッドは一度だけスキャンして実行できます。文字列を1回スキャンするCメソッドは、正しいことだと思います。
編集:
上記のコードを更新して、Python 3.5で動作し、現在最も投票されている回答のcheck_int関数を含め、整数フードのテストで見つけることができる現在最も人気のある正規表現を使用します。この正規表現は、「abc 123」のような文字列を拒否します。テスト値として「abc 123」を追加しました。
この時点で、tryメソッド、人気のあるcheck_int関数、および整数フードのテストで最も人気のある正規表現を含め、テストされた関数がどれもないことは、私にとって非常に興味深いことです。テスト値(まあ、正しい答えが何であるかによって異なります。以下のテスト結果を参照してください)。
組み込みのint()関数は、浮動小数点数が最初に文字列に変換されない限り、浮動小数点数の小数部を暗黙的に切り捨て、10進数の前の整数部を返します。
check_int()関数は、0.0や1.0(技術的には整数)などの値に対してfalseを返し、'06 'のような値に対してtrueを返します。
現在の(Python 3.5)テスト結果は次のとおりです。
isInt_try | isInt_str | isInt_re | isInt_re2 | check_int |
0 True | True | True | True | True |
1 True | True | True | True | True |
-1 True | True | True | True | True |
1.0 True | True | False | False | False |
-1.0 True | True | False | False | False |
'0' True | True | True | True | True |
'0.' False | True | False | False | False |
'0.0' False | True | False | False | False |
'1' True | True | True | True | True |
'-1' True | True | True | True | True |
'+1' True | True | True | True | True |
'1.0' False | True | False | False | False |
'-1.0' False | True | False | False | False |
'+1.0' False | True | False | False | False |
'06' True | True | False | False | True |
'abc 123' False | False | False | False | False |
1.1 True | False | False | False | False |
-1.1 True | False | False | False | False |
'1.1' False | False | False | False | False |
'-1.1' False | False | False | False | False |
'+1.1' False | False | False | False | False |
'1.1.1' False | False | False | False | False |
'1.1.0' False | False | False | False | False |
'1.0.1' False | False | False | False | False |
'1.0.0' False | False | False | False | False |
'1.0.' False | False | False | False | False |
'1..0' False | False | False | False | False |
'1..' False | False | False | False | False |
'0.0.' False | False | False | False | False |
'0..0' False | False | False | False | False |
'0..' False | False | False | False | False |
'one' False | False | False | False | False |
<obj..> False | False | False | False | False |
(1, 2, 3) False | False | False | False | False |
[1, 2, 3] False | False | False | False | False |
{'one': 'two'} False | False | False | False | False |
' 0 ' True | True | True | True | False |
' 0.' False | True | False | False | False |
' .0' False | False | False | False | False |
'.01 ' False | False | False | False | False |
ちょうど今、私はこの関数を追加してみました:
def isInt_float(s):
try:
return float(str(s)).is_integer()
except:
return False
check_int(0.3486)とほぼ同じように機能し、1.0と0.0、+ 1.0と0、.0などの値に対してtrueを返します。しかし、06の場合もtrueを返すので、毒を選んでくださいね。
try
ではより効率的です:isInt_try:0.6552 / isInt_str:0.6396 / isInt_re:1.0296 / isInt_re2:0.5168。
str.isdigit()
トリックを行う必要があります。
例:
str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False
編集:@BuzzMoschettiが指摘したように、この方法はマイナス数(たとえば、「-23」)では失敗します。input_numが0未満になる可能性がある場合は、str.isdigit()を適用する前にre.sub(regex_search、regex_replace、contents)を使用してください。例えば:
import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True
正規表現を使用します。
import re
def RepresentsInt(s):
return re.match(r"[-+]?\d+$", s) is not None
小数も受け入れる必要がある場合:
def RepresentsInt(s):
return re.match(r"[-+]?\d+(\.0*)?$", s) is not None
これを頻繁に行う場合にパフォーマンスを向上させるには、を使用して正規表現を1回だけコンパイルしre.compile()
ます。
適切なRegExソリューションは、Greg HewgillとNowellのアイデアを組み合わせますが、グローバル変数を使用しません。これを行うには、メソッドに属性を付加します。また、メソッドにインポートを配置することは不快であることを知っていますが、私がしようとしているのは、http://peak.telecommunity.com/DevCenter/Importing#lazy-importsのような「遅延モジュール」効果です。
編集:これまでのところ私のお気に入りのテクニックは、Stringオブジェクトのメソッドのみを使用することです。
#!/usr/bin/env python
# Uses exclusively methods of the String object
def isInteger(i):
i = str(i)
return i=='0' or (i if i.find('..') > -1 else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
# Uses re module for regex
def isIntegre(i):
import re
if not hasattr(isIntegre, '_re'):
print("I compile only once. Remove this line when you are confident in that.")
isIntegre._re = re.compile(r"[-+]?\d+(\.0*)?$")
return isIntegre._re.match(str(i)) is not None
# When executed directly run Unit Tests
if __name__ == '__main__':
for obj in [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0',
# non-integers
1.1, -1.1, '1.1', '-1.1', '+1.1',
'1.1.1', '1.1.0', '1.0.1', '1.0.0',
'1.0.', '1..0', '1..',
'0.0.', '0..0', '0..',
'one', object(), (1,2,3), [1,2,3], {'one':'two'}
]:
# Notice the integre uses 're' (intended to be humorous)
integer = ('an integer' if isInteger(obj) else 'NOT an integer')
integre = ('an integre' if isIntegre(obj) else 'NOT an integre')
# Make strings look like strings in the output
if isinstance(obj, str):
obj = ("'%s'" % (obj,))
print("%30s is %14s is %14s" % (obj, integer, integre))
そして、クラスの冒険好きではないメンバーのために、ここに出力があります:
I compile only once. Remove this line when you are confident in that.
0 is an integer is an integre
1 is an integer is an integre
-1 is an integer is an integre
1.0 is an integer is an integre
-1.0 is an integer is an integre
'0' is an integer is an integre
'0.' is an integer is an integre
'0.0' is an integer is an integre
'1' is an integer is an integre
'-1' is an integer is an integre
'+1' is an integer is an integre
'1.0' is an integer is an integre
'-1.0' is an integer is an integre
'+1.0' is an integer is an integre
1.1 is NOT an integer is NOT an integre
-1.1 is NOT an integer is NOT an integre
'1.1' is NOT an integer is NOT an integre
'-1.1' is NOT an integer is NOT an integre
'+1.1' is NOT an integer is NOT an integre
'1.1.1' is NOT an integer is NOT an integre
'1.1.0' is NOT an integer is NOT an integre
'1.0.1' is NOT an integer is NOT an integre
'1.0.0' is NOT an integer is NOT an integre
'1.0.' is NOT an integer is NOT an integre
'1..0' is NOT an integer is NOT an integre
'1..' is NOT an integer is NOT an integre
'0.0.' is NOT an integer is NOT an integre
'0..0' is NOT an integer is NOT an integre
'0..' is NOT an integer is NOT an integre
'one' is NOT an integer is NOT an integre
<object object at 0x103b7d0a0> is NOT an integer is NOT an integre
(1, 2, 3) is NOT an integer is NOT an integre
[1, 2, 3] is NOT an integer is NOT an integre
{'one': 'two'} is NOT an integer is NOT an integre
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False
したがって、関数は次のようになります。
def is_int(val):
return val[1].isdigit() and val.lstrip("-+").isdigit()
Greg Hewgillのアプローチにはいくつかのコンポーネントがありませんでした。文字列の先頭のみに一致する先頭の "^"と、事前にreをコンパイルしています。ただし、このアプローチでは、次のような試みを回避できます。
import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
return INT_RE.match(str(s)) is not None
なぜあなたがトライを避けようとしているのか興味があります。
私はいつもこれをしなければならず、try / exceptパターンを使用するのは穏やかですが明らかに非合理的な嫌悪があります。私はこれを使います:
all([xi in '1234567890' for xi in x])
負の数は受け入れられないため、マイナス記号(ある場合)を1つ取り除き、結果が0〜9の数字で構成されているかどうかを確認できます。
all([xi in '1234567890' for xi in x.replace('-', '', 1)])
入力が文字列かどうかわからない場合は、xをstr()に渡すこともできます。
all([xi in '1234567890' for xi in str(x).replace('-', '', 1)])
これがバラバラになる少なくとも2つの(エッジ?)ケースがあります。
type(1E2)
います<class 'float'>
のに対しtype(10^2)
提供します<class 'int'>
。したがって、すべての入力に対して機能するわけではありませんが、科学表記法、指数表記法、および空の文字列を除外できるFalse
場合、xが整数ではなく、xが整数であるTrue
場合に返されるOK 1行チェックです。
それがpythonicかどうかはわかりませんが、1行で、コードの動作は比較的明確です。
all(xi in '1234567890' for xi in x])
パターンは芝生の上を歩く許可を求めるようなものです。私は許可を求める人であることに興奮していませんが、ここにいます。
おもう
s.startswith('-') and s[1:].isdigit()
次のように書き換えた方がよいでしょう:
s.replace('-', '').isdigit()
s [1:]も新しい文字列を作成するため
しかし、はるかに良い解決策は
s.lstrip('+-').isdigit()
replace
しますか?また、これは5-2
、たとえばを誤って受け入れます。
s='-'
Shavaisの投稿は本当に気に入りましたが、テストケースをもう1つ追加しました(組み込みのisdigit()関数)。
def isInt_loop(v):
v = str(v).strip()
# swapping '0123456789' for '9876543210' makes nominal difference (might have because '1' is toward the beginning of the string)
numbers = '0123456789'
for i in v:
if i not in numbers:
return False
return True
def isInt_Digit(v):
v = str(v).strip()
return v.isdigit()
そして、それは残りの時代を著しく一貫して打ち負かしています:
timings..
isInt_try: 0.4628
isInt_str: 0.3556
isInt_re: 0.4889
isInt_re2: 0.2726
isInt_loop: 0.1842
isInt_Digit: 0.1577
通常の2.7 Pythonを使用:
$ python --version
Python 2.7.10
私が追加した2つのテストケース(isInt_loopとisInt_digit)はまったく同じテストケースに合格します(どちらも符号なし整数のみを受け入れます)が、組み込みのisdigitとは対照的に、文字列の実装(isInt_loop)を変更する方が賢いと考えました()関数なので、実行時間にわずかな違いはありますが、含めました。(そしてどちらの方法も他のすべてのものを大幅に上回っていますが、余分なものは処理しません: "./+/-")
また、2012年(現在は2018年)にShavaisが実行したのと同じテストで、正規表現(isInt_re2メソッド)が文字列比較を上回ったことに注目するのは興味深いことでした。正規表現ライブラリが改善されたのでしょうか?
エラーを発生させずに解析する関数を次に示します。None
失敗した場合に返される明らかなケースを処理します(CPythonではデフォルトで最大2000の「-/ +」記号を処理します!):
#!/usr/bin/env python
def get_int(number):
splits = number.split('.')
if len(splits) > 2:
# too many splits
return None
if len(splits) == 2 and splits[1]:
# handle decimal part recursively :-)
if get_int(splits[1]) != 0:
return None
int_part = splits[0].lstrip("+")
if int_part.startswith('-'):
# handle minus sign recursively :-)
return get_int(int_part[1:]) * -1
# successful 'and' returns last truth-y value (cast is always valid)
return int_part.isdigit() and int(int_part)
いくつかのテスト:
tests = ["0", "0.0", "0.1", "1", "1.1", "1.0", "-1", "-1.1", "-1.0", "-0", "--0", "---3", '.3', '--3.', "+13", "+-1.00", "--+123", "-0.000"]
for t in tests:
print "get_int(%s) = %s" % (t, get_int(str(t)))
結果:
get_int(0) = 0
get_int(0.0) = 0
get_int(0.1) = None
get_int(1) = 1
get_int(1.1) = None
get_int(1.0) = 1
get_int(-1) = -1
get_int(-1.1) = None
get_int(-1.0) = -1
get_int(-0) = 0
get_int(--0) = 0
get_int(---3) = -3
get_int(.3) = None
get_int(--3.) = 3
get_int(+13) = 13
get_int(+-1.00) = -1
get_int(--+123) = 123
get_int(-0.000) = 0
あなたのニーズのためにあなたは使うことができます:
def int_predicate(number):
return get_int(number) is not None
私は以下を提案します:
import ast
def is_int(s):
return isinstance(ast.literal_eval(s), int)
ドキュメントから:
式ノードまたはPythonリテラルまたはコンテナー表示を含む文字列を安全に評価します。提供される文字列またはノードは、文字列、バイト、数値、タプル、リスト、辞書、セット、ブール値、およびNoneのPythonリテラル構造のみで構成されます。
ValueError
Pythonリテラルを構成しないものに対して呼び出されると、例外が発生することに注意してください。質問はtry / exceptなしの解決策を求めていたので、私はそのための小林丸タイプの解決策を持っています:
from ast import literal_eval
from contextlib import suppress
def is_int(s):
with suppress(ValueError):
return isinstance(literal_eval(s), int)
return False
¯\ _(ツ)_ /¯
try / exceptには時間のペナルティがあるため、質問は速度に関連していると思います。
まず、200個の文字列、100個の失敗した文字列、100個の数値文字列のリストを作成しました。
from random import shuffle
numbers = [u'+1'] * 100
nonumbers = [u'1abc'] * 100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)
np.core.defchararray.isnumericは、Unicode文字列でも機能しますnp.core.defchararray.isnumeric(u'+12')
が、配列を返します。したがって、何千もの変換を行う必要があり、データが欠落している、または数値以外のデータがある場合は、これが優れたソリューションです。
import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)
10000 loops, best of 3: 27.9 µs per loop # 200 numbers per loop
def check_num(s):
try:
int(s)
return True
except:
return False
def check_list(l):
return [check_num(e) for e in l]
%timeit check_list(testlist)
1000 loops, best of 3: 217 µs per loop # 200 numbers per loop
numpyソリューションははるかに速いようです。
小文字のASCII数字のみを受け入れる場合は、次のテストを行ってください。
Python 3.7以降: (u.isdecimal() and u.isascii())
Python <= 3.6: (u.isdecimal() and u == str(int(u)))
他の回答では、.isdigit()
またはを使用することをお勧めします.isdecimal()
が、どちらにも'٢'
(u'\u0662'
)などの上位ユニコード文字が含まれています。
u = u'\u0662' # '٢'
u.isdigit() # True
u.isdecimal() # True
u.isascii() # False (Python 3.7+ only)
u == str(int(u)) # False
int()
。これらはどちらもによって適切に処理されます。
ええと。これを試してください:
def int_check(a):
if int(a) == a:
return True
else:
return False
これは、数値ではない文字列を入力しない場合に機能します。
また、(数字のチェック部分を置くのを忘れていました。)文字列が数字かどうかをチェックする関数があります。str.isdigit()です。次に例を示します。
a = 2
a.isdigit()
a.isdigit()を呼び出すと、Trueが返されます。
2
割り当てられた値を引用符で囲む必要があると思いますa
。