Bir dizenin bir tamsayı temsil edip etmediğini söylemenin bir yolu var mı (örn. '3'
, '-17'
Ama değil '3.14'
veya 'asfasfas'
) Try / hariç mekanizması kullanmadan?
is_int('3.14') = False
is_int('-7') = True
Bir dizenin bir tamsayı temsil edip etmediğini söylemenin bir yolu var mı (örn. '3'
, '-17'
Ama değil '3.14'
veya 'asfasfas'
) Try / hariç mekanizması kullanmadan?
is_int('3.14') = False
is_int('-7') = True
Yanıtlar:
S'yi try/except
her yerde kullanmaktan gerçekten rahatsızsanız , lütfen sadece bir yardımcı işlev yazın:
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False
Python'un tamsayı olarak kabul ettiği tüm dizeleri tam olarak kapsayacak şekilde WAY daha fazla kod olacak. Ben sadece bu konuda pitonik diyorum.
>>> print RepresentsInt(10.0)
True
>>> print RepresentsInt(10.06)
True
pozitif tamsayılarla kullanabilirsiniz .isdigit
:
>>> '16'.isdigit()
True
negatif tamsayılarla çalışmaz. aşağıdakileri deneyebileceğinizi varsayalım:
>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True
bu anlamda döküme '16.0'
benzer biçimle çalışmaz int
.
düzenleme :
def check_int(s):
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
u'²'.isdigit()
doğrudur ancak int(u'²')
ValueError değerini yükseltir. u.isdecimal()
Bunun yerine kullanın . str.isdigit()
yerel olarak Python 2'ye bağlıdır.
check_int('')
dönmek yerine bir istisna oluşturacakFalse
Biliyor musun, denedim / hariç bu nedenden ötürü iyi performans göstermediğini buldum (ve bunu tekrar tekrar test ettim). Sık sık bir şeyler yapmanın birkaç yolunu deniyorum ve şimdiye kadar test edilenlerin en iyisini yapmak için dene / kullan'ı kullanan bir yöntem bulduğumu sanmıyorum, aslında bana göre bu yöntemler genellikle en kötü, en kötü değilse. Her durumda değil, birçok durumda. Bir çok insanın "Pitonik" yol olduğunu söylediğini biliyorum, ama bu, onlarla birlikte ayrıldığım bir alan. Bana göre, ne çok performanslı ne de çok zarif, bu yüzden sadece hata yakalama ve raporlama için kullanma eğilimindeyim.
PHP, perl, yakut, C ve hatta ucube kabuğun tamsayı-başlık için bir dizeyi test etmek için basit işlevlere sahip olduğunu kavrayacaktım, ancak bu varsayımları doğrulamak için gereken özveri beni tetikledi! Görünüşe göre bu eksiklik yaygın bir hastalıktır.
İşte Bruno'nun gönderisinin hızlı ve kirli bir düzenlemesi:
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))
İşte performans karşılaştırma sonuçları:
timings..
isInt_try: 0.6426
isInt_str: 0.7382
isInt_re: 1.1156
isInt_re2: 0.5344
check_int: 0.3452
AC yöntemi bir kez tarayabilir ve yapılabilir. Dize bir kez tarar AC yöntemi yapmak için doğru şey olacağını düşünüyorum.
DÜZENLE:
Python 3.5'te çalışmak ve şu anda en çok oylanan cevaptan check_int işlevini dahil etmek ve tamsayı kaputu için test için bulabildiğim en popüler normal ifadeyi kullanmak için yukarıdaki kodu güncelledim. Bu normal ifade 'abc 123' gibi dizeleri reddediyor. Test değeri olarak 'abc 123' ekledim.
Bu noktada, try yöntemi, popüler check_int fonksiyonu ve integer-hood test için en popüler regex dahil olmak üzere test edilen fonksiyonlardan HİÇBİRİ'nin, test değerleri (doğru cevapların ne olduğunu düşündüğünüze bağlı olarak; aşağıdaki test sonuçlarına bakın).
Yerleşik int () işlevi, kayan nokta numarasının kesirli kısmını sessizce keser ve kayan nokta numarası ilk olarak bir dizeye dönüştürülmediği sürece ondalık sayıdan önce tam sayı kısmını döndürür.
Check_int () işlevi 0.0 ve 1.0 gibi değerler için (teknik olarak tamsayıdır) false değerini döndürür ve '06' gibi değerler için true değerini döndürür.
Şu anki (Python 3.5) test sonuçları:
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 |
Hemen şimdi bu işlevi eklemeyi denedim:
def isInt_float(s):
try:
return float(str(s)).is_integer()
except:
return False
Neredeyse check_int (0.3486) kadar iyi performans gösterir ve 1.0 ve 0.0 ve +1.0 ve 0. ve .0 gibi değerler için true değerini döndürür. Ama aynı zamanda '06' için de doğrudur. Zehirini seç, sanırım.
try
3.5'te daha verimlidir: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
str.isdigit()
hile yapmalı.
Örnekler:
str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False
DÜZENLEME : @BuzzMoschetti'nin işaret ettiği gibi, bu yol eksi sayı için başarısız olacaktır (örneğin, "-23" ). Durumda sizin input_num az 0'dan olabilir, kullanım re.sub (regex_search, regex_replace, içindekiler) uygulamadan önce str.isdigit () . Örneğin:
import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True
Normal bir ifade kullanın:
import re
def RepresentsInt(s):
return re.match(r"[-+]?\d+$", s) is not None
Ondalık kesirleri de kabul etmeniz gerekiyorsa:
def RepresentsInt(s):
return re.match(r"[-+]?\d+(\.0*)?$", s) is not None
Bunu sık sık artırıyorsanız, düzenli ifadeyi yalnızca bir kez kullanarak derleyin re.compile()
.
Uygun RegEx çözümü Greg Hewgill ve Nowell'in fikirlerini birleştirir, ancak global bir değişken kullanmaz. Yönteme bir öznitelik ekleyerek bunu başarabilirsiniz. Ayrıca, bir yöntemde ithalat koymak için kaşlarını çattı biliyorum, ama ben gidiyorum http://peak.telecommunity.com/DevCenter/Importing#lazy-imports gibi bir "tembel modül" etkisi
edit: Şimdiye kadar benim en sevdiğim teknik yalnızca String nesnesinin yöntemlerini kullanmaktır.
#!/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))
Ve sınıfın daha az maceracı üyeleri için, çıktı:
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
Yani fonksiyonunuz:
def is_int(val):
return val[1].isdigit() and val.lstrip("-+").isdigit()
Greg Hewgill'in yaklaşımında birkaç bileşen eksikti: önde gelen "^" sadece dizenin başlangıcıyla eşleşecek ve re'yi önceden derleyecekti. Ancak bu yaklaşım denemekten kaçınmanıza izin verecektir: exept:
import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
return INT_RE.match(str(s)) is not None
Neden denemekten kaçınmaya çalıştığınızı merak ediyorum: hariç?
Bunu her zaman yapmak zorundayım ve denemek / hariç tutmak için hafif ama kuşkusuz mantıksız bir isteksizlik var. Bunu kullanıyorum:
all([xi in '1234567890' for xi in x])
Negatif sayıları barındırmaz, bu nedenle (varsa) bir eksi işareti çıkarabilir ve sonucun 0-9 arasındaki rakamları içerip içermediğini kontrol edebilirsiniz:
all([xi in '1234567890' for xi in x.replace('-', '', 1)])
Girişin bir dize olduğundan emin değilseniz x'i str () öğesine de iletebilirsiniz:
all([xi in '1234567890' for xi in str(x).replace('-', '', 1)])
Bunun parçalandığı en az iki (kenar?) Vaka vardır:
type(1E2)
verir <class 'float'>
oysa type(10^2)
verir <class 'int'>
.Bu nedenle, olası her giriş için işe yaramaz , ancak bilimsel gösterimi, üstel gösterimi ve boş dizeleri hariç tutabiliyorsanız, False
x bir tamsayı True
değilse ve x bir tamsayı ise dönen tek satırlık bir kontroldür .
Pythonic olup olmadığını bilmiyorum, ama bir satır, ve kodun ne yaptığı nispeten açık.
all(xi in '1234567890' for xi in x])
desen daha çim üzerinde yürümek için izin istemek gibi görünüyor. İzinli asker olmaktan heyecan duymuyorum, ama işte buradayız.
bence
s.startswith('-') and s[1:].isdigit()
yeniden yazmak daha iyi olur:
s.replace('-', '').isdigit()
çünkü s [1:] ayrıca yeni bir dize oluşturur
Ama çok daha iyi bir çözüm
s.lstrip('+-').isdigit()
replace
yapıyor? Ayrıca, bu yanlış bir şekilde kabul edecektir 5-2
.
s='-'
Shavais'in gönderisini gerçekten beğendim, ancak bir test örneği daha ekledim (& yerleşik isdigit () işlevi):
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()
ve dinlenme zamanlarını önemli ölçüde tutarlı bir şekilde yener:
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
normal 2.7 python kullanarak:
$ python --version
Python 2.7.10
Eklediğim her iki test vakası (isInt_loop ve isInt_digit) tam olarak aynı test durumlarını geçiyor (her ikisi de sadece imzasız tam sayıları kabul ediyor), ancak insanların yerleşik isdigit'in aksine dize uygulamasını (isInt_loop) değiştirerek daha akıllı olabileceğini düşündüm. () işlevi, bu yüzden yürütme süresinde küçük bir fark olmasına rağmen dahil ettim. (ve her iki yöntem de diğer her şeyi çok fazla dövüyor, ancak fazladan şeylerle başa çıkma: "./+/-")
Ayrıca, regex'in (isInt_re2 yöntemi) Shavais tarafından 2012'de (şu anda 2018) gerçekleştirilen aynı testte dize karşılaştırmasını yendiğini belirtmek ilginç buldum. Belki normal ifade kütüphaneleri geliştirildi?
Bu muhtemelen bence ona yaklaşmanın en basit ve pythonic yoludur. Bu çözümü görmedim ve temel olarak normal ifade ile aynı, ama normal ifade olmadan.
def is_int(test):
import string
return not (set(test) - set(string.digits))
set(input_string) == set(string.digits)
Biz atlarsanız '-+ '
başında ve .0
, E-1
sonunda.
İşte hataları yükseltmeden ayrıştırma işlevi. Açıkça None
başarısızlık durumunda geri dönüşleri işler (CPython'da varsayılan olarak 2000 '- / +' işaretlerine kadar işler!):
#!/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)
Bazı testler:
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)))
Sonuçlar:
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
İhtiyaçlarınız için şunları kullanabilirsiniz:
def int_predicate(number):
return get_int(number) is not None
Aşağıdakileri öneririm:
import ast
def is_int(s):
return isinstance(ast.literal_eval(s), int)
Gönderen docs :
Bir ifade düğümünü veya Python hazır bilgisi veya kapsayıcı görüntüsü içeren bir dizeyi güvenle değerlendirin. Sağlanan dize veya düğüm yalnızca şu Python değişmez yapılarından oluşabilir: dizeler, baytlar, sayılar, tuples, listeler, dikteler, kümeler, booleans ve Yok.
ValueError
Bir Python hazır bilgisi oluşturmayan herhangi bir şeye karşı çağrıldığında bunun bir istisna yaratacağına dikkat etmeliyim . Soru denemeden / hariç bir çözüm istediğinden, bunun için bir Kobayashi-Maru tipi çözümüm var:
from ast import literal_eval
from contextlib import suppress
def is_int(s):
with suppress(ValueError):
return isinstance(literal_eval(s), int)
return False
¯ \ _ (ツ) _ / ¯
Sanırım bu denemenin hızla ilgiliydi, çünkü dene / hariç bir zaman cezası var:
İlk olarak 200 dize, 100 başarısız dize ve 100 sayısal dize listesi oluşturdum.
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 ayrıca unicode dizeleriyle de çalışabilir, np.core.defchararray.isnumeric(u'+12')
ancak geri döner ve dizidir. Bu nedenle, binlerce dönüşüm yapmanız ve eksik veya sayısal olmayan verileriniz olması iyi bir çözümdür.
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 çözümünün çok daha hızlı olduğu anlaşılıyor.
Yalnızca düşük ascii basamaklarını kabul etmek istiyorsanız, bunu yapmak için testler şunlardır:
Python 3.7+: (u.isdecimal() and u.isascii())
Python <= 3.6: (u.isdecimal() and u == str(int(u)))
Diğer yanıtlar .isdigit()
ya kullanmanızı önerir, .isdecimal()
ancak bunların her ikisi de '٢'
( u'\u0662'
) gibi bazı üst unicode karakterleri içerir :
u = u'\u0662' # '٢'
u.isdigit() # True
u.isdecimal() # True
u.isascii() # False (Python 3.7+ only)
u == str(int(u)) # False
int()
.
Ah .. Şunu deneyin:
def int_check(a):
if int(a) == a:
return True
else:
return False
Bu sayı olmayan bir dize koymazsanız çalışır.
Ve ayrıca (sayı kontrol bölümünü koymayı unuttum.), Dize bir sayı olup olmadığını kontrol eden bir işlev var. Str.isdigit () şeklindedir. İşte bir örnek:
a = 2
a.isdigit()
A.isdigit () öğesini çağırırsanız True döndürür.
2
atanmış değeri etrafında tırnak gerekir düşünüyorum a
.