Bir dizenin try / hariç kullanmadan int'i temsil edip etmediğini nasıl kontrol edebilirim?


468

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

23
Neden ikisi de bunu "zor yoldan" yapmaya çalışıyor? Deneyin / hariç yanlış olan ne?
S.Lott

5
Evet, deneme / hariç yanlış olan ne? Affetmek için izin istemekten daha iyidir.
mk12

53
Neden bu basit şey denemek gerekir dışında sormak istiyorum? İstisna sistemi karmaşık bir canavardır, ancak bu basit bir sorundur.
Aivar

13
@Aivar FUD yaymayı bırak. Tek bir deneme / blok hariç "karmaşık" bile yaklaşmaz.
Triptik

47
Yine de gerçekten FUD değil. Etkili bir şekilde 4 satır kod yazacak, bir şeyin patlamasını bekleyecek, bu istisnayı yakalayacak ve tek bir astar kullanmak yerine varsayılanınızı yapacaksınız.
andersonvom

Yanıtlar:


398

S'yi try/excepther 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.


124
Karmaşık mekanizma ile basit problemi çözmek pitonik mi? İnt'in "int" fonksiyonunun içinde yazılı olduğunu tespit etmek için bir algoritma var - bunun neden bir boole fonksiyonu olarak gösterilmediğini anlamıyorum.
Aivar

79
@Aivar: Bu 5 satır işlevi karmaşık bir mekanizma değildir.
Triptik

34
Dışında:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Dannid

5
Sanırım Python dizenin bir int olduğunu düşünüyorsa, programınız da "pythonic". Python değişirse, programınız da değişir ve tek bir kod satırını değiştirmeden. Bunda bir değer var. Koşullara bağlı olarak yapılacak doğru şey olabilir.
Shavais

57
Bunun neden kabul edilen cevap olduğunu veya çok fazla oyu olduğunu bilmiyorum, çünkü bu OP'nin istediği şeyin tam tersidir.
FearlessFuture

758

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()

6
bu ek bir özel durum olmadan "+17" ile başa çıkmaz.
Bryan Oakley

1
BOTH vakalarını test etmeniz gerekir: lambda s: s.isdigit () veya (s.startswith ('-') ve s [1:]. İsdigit ())
rob

4
@Roberto: Tabii ki yapmalısın! ve eminim ki bunu yapabilirsin!
SilentGhost

22
not: 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.
jfs

4
check_int('')dönmek yerine bir istisna oluşturacakFalse
wordbug

97

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.


Belki de bir kısmı, bir tamsayının biraz keyfi olması gerçeğinden kaynaklanır. Bir programlama sistemi, her zaman ondalık bir temsil olacağını varsaymak lüksünü alamaz. 0x4df, bazı yerlerde geçerli bir tam sayı ve 0891 diğerlerinde değil. Bu tür kontrollerde unicode verildiğinde ne ortaya çıkabileceğini düşünmekten korkuyorum.
PlexQ

3
Zamanlama için +1. Bu istisna işinin böylesine basit bir soru için gerçekten zarif olmadığını kabul ediyorum. Böylesine yaygın bir sorun için yardımcı bir yöntem geliştirmeyi beklersiniz ...
RickyA

9
Bu iş parçacığı temelde uykuda olduğunu, ancak +1 çalışma zamanı dikkate almak için biliyorum. Çizgi uzunluğu her zaman altta yatan karmaşıklığın göstergesi değildir; ve tabii, bir kudreti bir görünüm basit hariç deneme / ama (ve çok önemli olan, kolay okunur) olan pahalı bir işlem. Tercih hiyerarşisinin her zaman aşağıdaki gibi görünmesi gerektiğini savunuyorum: 1. Kolay okunan açık bir çözüm (SilentGhost's). 2. Okunması kolay bir örtük çözüm (Triptych's). 3. Üç yok.
Eric Humphrey

1
Bu kadar önemsiz görünen bir konuyla ilgili kapsamlı araştırmalarınız için teşekkür ederiz. Ben pitonik ya da değil isInt_str () ile gidiyorum. Beni rahatsız eden şey, v.find ('..') anlamı hakkında hiçbir şey bulamadığım. Bu bir tür özel find-sözdizimi mi, yoksa sayısal bir dizenin uç vakası mı?
JackLeEmmerdeur

3
Evet, biraz tarihli ama yine de gerçekten güzel ve ilgili analiz. Python try3.5'te daha verimlidir: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
Dave

40

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

1
Çünkü -23 yanlış verir.
Buzz Moschetti

1
@BuzzMoschetti haklısın. Düzeltmenin hızlı bir yolu, str.isdigit () uygulamadan önce re.replace (regex_search, regex_replace, içindekiler) eksi işaretini kaldırmaktır
Catbuilts

27

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().


19
+1: bunun try / hariç ile karşılaştırıldığında korkunç derecede karmaşık ve pahalı olduğunu ortaya koyuyor.
S.Lott

2
Bunun aslında @SilentGhost tarafından sunulan 'isnumeric' çözümünün daha yavaş ve özel bir sürümü olduğunu hissediyorum.
Greg

@Greg: @SilentGhost işaretleri doğru şekilde kapsamadığından, bu sürüm aslında çalışır.
S.Lott

1
@ S.Lott: Şüphesiz, SO'ya yazı gönderebilen herkes, örneğimi işaretleri kapsayacak şekilde genişletebilir.
SilentGhost

2
düzenli ifadeler var olan en karmaşık ve belirsiz şeyle ilgilidir, yukarıdaki basit kontrolün çok daha açık olduğunu görüyorum, hala çirkin olduğunu düşünsem bile, bu daha çirkin.
PlexQ

18

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

4
Test takımımın aşırı dolu olduğunu kabul edeceğim. Kodumu yazarken işe yaradığını kanıtlamayı seviyorum . Ama sence isInteger fonksiyonum aşırıya kaçmış mı? Kesinlikle hayır.
Bruno Bronosky

1
Henüz yorum yapmadan bir aşağı oy aldım. İnsanlarda ne var? Y kuşağının artık "Beğeniler" i "okundu bilgileri" olarak kullandığını anlıyorum. Ama şimdi oyları "seçtiğim yöntem değil" işaretleri olarak mı kullanıyorlar? Belki de KENDİ saygınlığınızdan 2 puan çıkardığının bir cevabı aşağı indirdiğinin farkında değiller . SO / SE bunu sadece yanlış bilgilendirme nedeniyle oylamayı teşvik etmek için yapar, bu durumda bir yorum bırakacağınızı umarım .
Bruno Bronosky

5
>>> "+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()

1
is_int ("2") IndexError öğesini yükseltir.
anttikoo

4

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ç?


1
Bir stil meselesi. "Try / hariç" normal program akışı ile değil, sadece gerçek hatalarla kullanılması gerektiğini düşünüyorum.
Adam Matan

2
@Udi Pasmon: Python, "normal" program akışı dışında, try / den oldukça fazla kullanılır. Örneğin, her yineleyici istisna dışında durur.
S.Lott

3
-1: Normal ifadeyi derleme konusundaki ipucunuz doğru olsa da, Greg'i diğer açıdan eleştirmekte yanılıyorsunuz: re.match dizenin başlangıcıyla eşleşir , bu nedenle desendeki ^ aslında gereksizdir. (Bu yeniden arama kullandığınızda farklıdır).
ThomasH

S.Lott - Bu, python'da makul bir akış olarak mı kabul ediliyor? Bunun diğer dillerden farkı nedir? Belki de ayrı bir soruya değer.
Adam Matan

1
Python'un denemenin / hariç tutmanın yoğun kullanımı burada SO'da ele alınmıştır. '
S.Lott

4

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:

  1. Çeşitli bilimsel ve / veya üstel gösterimler için çalışmaz (örneğin 1.2E3, 10 ^ 3, vb.) - her ikisi de Yanlış döndürür. Diğer cevaplar ya bu ağırladı sanmıyorum, ve o zamandan beri hatta Python 3.8, tutarsız görüşler vardır type(1E2)verir <class 'float'>oysa type(10^2)verir <class 'int'>.
  2. Boş bir dize girişi True verir.

Bu nedenle, olası her giriş için işe yaramaz , ancak bilimsel gösterimi, üstel gösterimi ve boş dizeleri hariç tutabiliyorsanız, Falsex bir tamsayı Truedeğ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.


Denemek / hariç birinin çim üzerinde yürümek (denemek) gibi görünüyor ve sonra fark ve ne zaman onlar öfkeli (istisna) özür dilemek (istisna ele), oysa benim 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.
mRotten

3

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()

3
Tahmin et ne replaceyapıyor? Ayrıca, bu yanlış bir şekilde kabul edecektir 5-2.
Ry-

Eğer bir IndexError firlatirmisinizs='-'
Karşıtı Dünya

s = '-'; s.replace ('-', '') .isdigit () -> Yanlış
Vladyslav Savchenko

2

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?


1

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-1sonunda.
jfs

1

İşte hataları yükseltmeden ayrıştırma işlevi. Açıkça Nonebaş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

1

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.

ValueErrorBir 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

¯ \ _ (ツ) _ / ¯


0

Ben hiç int kullanmayan ve dize bir sayı temsil etmediği sürece bir istisna yükseltmemelidir bir olasılık var

float(number)==float(number)//1

Şamandıra kabul eden her türlü dize için çalışmalıdır, pozitif, negatif, mühendislik notasyonu ...


0

Sanırım bu denemenin hızla ilgiliydi, çünkü dene / hariç bir zaman cezası var:

 test verisi

İ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)

 numpy çözümü (yalnızca diziler ve unicode ile çalışır)

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

denemek / hariç

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.


0

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

Bu, negatif değerleri veya beyaz boşluklu dolgulu değerleri işlemez; bunların her ikisi de gayet iyi işlenir int().
ShadowRanger

-6

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.


Ben 2atanmış değeri etrafında tırnak gerekir düşünüyorum a.
Luke Woodward

1
Bu neden en iyi cevap değil? Soruyu tam olarak cevaplıyor.
çekirge

6
-1 sorusu: "Bir dizenin bir int temsil edip etmediğini kontrol et , Try / Except kullanmadan?" Karoline Alexiou
jfs için
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.