Làm thế nào tôi có thể kiểm tra nếu một chuỗi đại diện cho một int, mà không sử dụng try / ngoại trừ?


466

Có cách nào để biết liệu một chuỗi đại diện cho một số nguyên (ví dụ '3', '-17'nhưng không '3.14'hoặc 'asfasfas') mà không sử dụng cơ chế thử / ngoại trừ?

is_int('3.14') = False
is_int('-7')   = True

23
Tại sao cả hai cố gắng làm điều này "một cách khó khăn?" Có gì sai với thử / ngoại trừ?
S.Lott

5
Có, có gì sai với thử / ngoại trừ? Thà xin tha thứ còn hơn xin phép.
mk12

53
Tôi sẽ hỏi tại sao điều đơn giản này cần phải thử / ngoại trừ? Hệ thống ngoại lệ là một con thú phức tạp, nhưng đây là một vấn đề đơn giản.
Aivar

13
@Aivar ngừng lan truyền FUD. Một lần thử / ngoại trừ khối thậm chí không tiếp cận "phức tạp".
Triptych

47
Nó không thực sự FUD, mặc dù. Bạn sẽ viết 4 dòng mã một cách hiệu quả, hy vọng sẽ có thứ gì đó nổ tung, bắt ngoại lệ đó và thực hiện mặc định của bạn, thay vì sử dụng một dòng.
andersonvom

Câu trả lời:


398

Nếu bạn thực sự khó chịu khi sử dụng try/excepts ở mọi nơi, vui lòng chỉ viết một hàm trợ giúp:

def RepresentsInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False

Sẽ là CÁCH nhiều mã hơn để bao gồm chính xác tất cả các chuỗi mà Python coi là số nguyên. Tôi nói chỉ là pythonic về điều này.


124
Vì vậy, nó là pythonic để giải quyết vấn đề đơn giản với cơ chế phức tạp? Có một thuật toán để phát hiện hàm int được viết bên trong "int" - Tôi không hiểu tại sao điều này không được phơi bày dưới dạng hàm boolean.
Aivar

79
@Aivar: Hàm 5 dòng này không phải là một cơ chế phức tạp.
Triptych

34
Ngoại trừ:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Dannid

5
Tôi đoán đó là "pythonic" theo nghĩa là nếu Python nghĩ chuỗi đó là int, thì chương trình của bạn cũng vậy. Nếu Python thay đổi, chương trình của bạn cũng vậy và không thay đổi một dòng mã nào. Có một số giá trị trong đó. Nó có thể là điều đúng đắn tùy thuộc vào hoàn cảnh.
Shavais

57
Tôi không biết tại sao đây là câu trả lời được chấp nhận hoặc có quá nhiều sự ủng hộ, vì điều này hoàn toàn ngược lại với những gì OP đang yêu cầu.
FearlessFuture

755

với số nguyên dương bạn có thể sử dụng .isdigit:

>>> '16'.isdigit()
True

mặc dù nó không hoạt động với số nguyên âm. giả sử bạn có thể thử như sau:

>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True

nó sẽ không hoạt động với '16.0'định dạng, tương tự như intđúc theo nghĩa này.

chỉnh sửa :

def check_int(s):
    if s[0] in ('-', '+'):
        return s[1:].isdigit()
    return s.isdigit()

6
điều này không xử lý "+17" mà không có trường hợp đặc biệt bổ sung.
Bryan Oakley

1
Bạn phải kiểm tra các trường hợp CẢ HAI: lambda s: s.itorigit () hoặc (s.startswith ('-') và s [1:]. Isdigit ())
cướp

4
@Roberto: tất nhiên là bạn nên! và tôi chắc chắn rằng bạn có khả năng làm như vậy!
SilentGhost

22
lưu ý: u'²'.isdigit()là đúng nhưng int(u'²')làm tăng ValueError. Sử dụng u.isdecimal()thay thế. str.isdigit()là phụ thuộc vào miền địa phương trên Python 2.
jfs

4
check_int('')sẽ đưa ra một ngoại lệ thay vì quay trở lạiFalse
wordbird

97

Bạn biết đấy, tôi đã tìm thấy (và tôi đã thử nghiệm điều này nhiều lần) rằng thử / ngoại trừ không thực hiện tốt tất cả, vì bất kỳ lý do gì. Tôi thường xuyên thử một số cách để làm mọi thứ và tôi không nghĩ rằng mình đã từng tìm thấy một phương pháp sử dụng thử / ngoại trừ để thực hiện tốt nhất những thử nghiệm đó, thực tế thì dường như những phương pháp đó thường xuất hiện gần với tồi tệ nhất, nếu không phải là tồi tệ nhất. Không phải trong mọi trường hợp, nhưng trong nhiều trường hợp. Tôi biết nhiều người nói đó là cách "Pythonic", nhưng đó là một lĩnh vực mà tôi chia tay với họ. Đối với tôi, nó không thực sự hay cũng rất thanh lịch, vì vậy, tôi có xu hướng chỉ sử dụng nó để bẫy và báo cáo lỗi.

Tôi sẽ nắm bắt rằng PHP, perl, ruby, C và thậm chí cả cái vỏ kỳ dị có các chức năng đơn giản để kiểm tra một chuỗi cho số nguyên, nhưng do sự chuyên cần trong việc xác minh những giả định đó đã làm tôi vấp ngã! Rõ ràng sự thiếu này là một căn bệnh phổ biến.

Đây là bản chỉnh sửa nhanh và bẩn của bài đăng của Bruno:

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

Dưới đây là kết quả so sánh hiệu suất:

timings..
isInt_try:   0.6426
isInt_str:   0.7382
isInt_re:    1.1156
isInt_re2:   0.5344
check_int:   0.3452

Phương pháp AC có thể quét nó một lần thông qua và được thực hiện. Phương pháp AC quét chuỗi một lần thông qua sẽ là Điều phải làm, tôi nghĩ vậy.

BIÊN TẬP:

Tôi đã cập nhật mã ở trên để hoạt động trong Python 3.5 và bao gồm hàm check_int từ câu trả lời được bình chọn nhiều nhất hiện nay và để sử dụng regex phổ biến nhất hiện tại mà tôi có thể tìm thấy để kiểm tra trình duyệt số nguyên. Regex này từ chối các chuỗi như 'abc 123'. Tôi đã thêm 'abc 123' làm giá trị thử nghiệm.

Điều thú vị đối với tôi là tại thời điểm này, KHÔNG CÓ các hàm được kiểm tra, bao gồm phương thức thử, hàm check_int phổ biến và biểu thức chính thức phổ biến nhất để kiểm tra trình số nguyên, trả về các câu trả lời đúng cho tất cả các giá trị kiểm tra (tốt, tùy thuộc vào những gì bạn nghĩ câu trả lời đúng; xem kết quả kiểm tra bên dưới).

Hàm int () tích hợp trong âm thầm cắt phần phân số của số dấu phẩy động và trả về phần nguyên trước số thập phân, trừ khi số dấu phẩy động đầu tiên được chuyển đổi thành một chuỗi.

Hàm check_int () trả về false cho các giá trị như 0.0 và 1.0 (về mặt kỹ thuật là số nguyên) và trả về true cho các giá trị như '06'.

Dưới đây là kết quả kiểm tra (Python 3.5) hiện tại:

                  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   |

Bây giờ tôi đã thử thêm chức năng này:

def isInt_float(s):
    try:
        return float(str(s)).is_integer()
    except:
        return False

Nó thực hiện gần như cũng như check_int (0.3486) và nó trả về true cho các giá trị như 1.0 và 0.0 và +1.0 và 0. và .0, v.v. Nhưng nó cũng trả về đúng cho '06', vì vậy. Chọn chất độc của bạn, tôi đoán.


Có lẽ một phần của nó xuất phát từ thực tế là một số nguyên là một chút tùy ý. Một hệ thống lập trình không thể có sự xa xỉ khi cho rằng nó luôn luôn là một biểu diễn thập phân. 0x4df, là một số nguyên hợp lệ ở một số nơi và 0891 không ở những nơi khác. Tôi sợ hãi khi nghĩ những gì có thể phát sinh được đưa ra unicode trong các loại kiểm tra này.
PlexQ

3
+1 cho thời gian. Tôi đồng ý rằng toàn bộ doanh nghiệp ngoại lệ này không thực sự thanh lịch cho một câu hỏi đơn giản như vậy. Bạn sẽ mong đợi một phương pháp xây dựng trong trình trợ giúp cho một vấn đề phổ biến như vậy ...
RickyA

9
Tôi biết chủ đề này về cơ bản là không hoạt động, nhưng +1 để xem xét thời gian chạy. Độ dài dòng không phải lúc nào cũng biểu thị độ phức tạp tiềm ẩn; và chắc chắn, một lần thử / ngoại trừ có thể trông đơn giản (và đọc dễ dàng, điều này cũng quan trọng), nhưng đó một hoạt động tốn kém. Tôi cho rằng hệ thống phân cấp ưu tiên sẽ luôn trông giống như sau: 1. Một giải pháp rõ ràng dễ đọc (SilentGhost's). 2. Một giải pháp ngầm dễ đọc (Triptych's). 3. Không có ba.
Eric Humphrey

1
Cảm ơn cho các cuộc điều tra tourough của bạn liên quan đến một chủ đề dường như không đáng kể. Tôi sẽ đi với isInt_str (), pythonic hay không. Điều làm tôi khó chịu là tôi chưa tìm thấy gì về ý nghĩa của v.find ('..'). Đó có phải là một loại cú pháp tìm kiếm đặc biệt hoặc trường hợp cạnh của chuỗi số không?
JackLeEmmerdeur

3
Vâng, một chút ngày nhưng vẫn thực sự tốt đẹp và phân tích có liên quan. Trong Python 3.5 tryhiệu quả hơn: isInt_try: 0.6552 / isInt_str: 0.6394 / isInt num: 1.0296 / isInt num2: 0.5168.
Dave

39

str.isdigit() nên làm thủ thuật.

Ví dụ:

str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False

EDIT : Như @BuzzMoschetti đã chỉ ra, cách này sẽ không thành công cho số trừ (ví dụ: "-23" ). Trong trường hợp input_num của bạn có thể nhỏ hơn 0, hãy sử dụng re.sub (regex_search, regex numplace, nội dung) trước khi áp dụng str.itorigit () . Ví dụ:

import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True

1
Vì -23 mang lại sai.
Buzz Moschetti

1
@BuzzMoschetti bạn nói đúng. Một cách nhanh chóng để khắc phục là xóa dấu trừ bằng re.replace (regex_search, regex numplace, nội dung) trước khi áp dụng str.itorigit ()
Catbuilts

27

Sử dụng một biểu thức thông thường:

import re
def RepresentsInt(s):
    return re.match(r"[-+]?\d+$", s) is not None

Nếu bạn cũng phải chấp nhận phân số thập phân:

def RepresentsInt(s):
    return re.match(r"[-+]?\d+(\.0*)?$", s) is not None

Để cải thiện hiệu suất nếu bạn đang làm điều này thường xuyên, hãy biên dịch biểu thức chính quy chỉ một lần bằng cách sử dụng re.compile().


19
+1: tiết lộ rằng điều này phức tạp và tốn kém khủng khiếp khi so sánh với thử / ngoại trừ.
S.Lott

2
Tôi cảm thấy đây thực chất là một phiên bản tùy chỉnh chậm hơn của giải pháp 'isnumeric' được cung cấp bởi @SilentGhost.
Greg

@Greg: Vì @SilentGhost không bao gồm các dấu hiệu chính xác, phiên bản này thực sự hoạt động.
S.Lott

1
@ S.Lott: chắc chắn, bất cứ ai có khả năng đăng bài trên SO, đều có thể mở rộng ví dụ của tôi để che dấu hiệu.
SilentGhost

2
các biểu thức thông thường là về điều phức tạp và tối nghĩa nhất trong sự tồn tại, tôi thấy rằng kiểm tra đơn giản ở trên rõ ràng hơn rõ ràng, ngay cả khi tôi nghĩ nó vẫn xấu, điều này xấu hơn.
PlexQ

18

Giải pháp RegEx phù hợp sẽ kết hợp các ý tưởng của Greg Hewgill và Nowell, nhưng không sử dụng biến toàn cục. Bạn có thể thực hiện điều này bằng cách đính kèm một thuộc tính cho phương thức. Ngoài ra, tôi biết rằng việc đưa nhập khẩu vào một phương thức là điều không nên, nhưng điều tôi sẽ làm là hiệu ứng "mô-đun lười biếng" như http://peak.telecommunity.com/DevCenter/Importing#lazy-imports

chỉnh sửa: Kỹ thuật yêu thích của tôi cho đến nay là sử dụng các phương thức độc quyền của đối tượng 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))

Và đối với các thành viên ít phiêu lưu trong lớp, đây là đầu ra:

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
Tôi sẽ đồng ý rằng bộ thử nghiệm của tôi là quá mức cần thiết. Tôi muốn chứng minh rằng mã của tôi hoạt động khi tôi viết nó. Nhưng bạn có nghĩ rằng hàm isInteger của tôi là quá mức không? Chắc chắn là không.
Bruno Bronosky

1
Tôi chỉ nhận được một phiếu bầu không có ý kiến. Có chuyện gì với mọi người vậy? Tôi hiểu rằng millennials hiện đang sử dụng "Thích" làm "đọc biên lai". Nhưng bây giờ họ có sử dụng phiếu bầu là "không phải phương pháp tôi chọn" không? Có lẽ họ không nhận ra rằng nó trừ 2 điểm từ danh tiếng RIÊNG CỦA BẠN để bỏ phiếu trả lời. SO / SE làm điều đó để khuyến khích bỏ phiếu chỉ do thông tin sai, trong trường hợp đó tôi hy vọng bạn sẽ để lại nhận xét .
Bruno Bronosky

5
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False

Vì vậy, chức năng của bạn sẽ là:

def is_int(val):
   return val[1].isdigit() and val.lstrip("-+").isdigit()

1
is_int ("2") làm tăng IndexError.
anttikoo

4

Cách tiếp cận của Greg Hewgill đã thiếu một vài thành phần: "^" hàng đầu để chỉ khớp với phần đầu của chuỗi và biên dịch lại từ trước. Nhưng phương pháp này sẽ cho phép bạn tránh thử: exept:

import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
    return INT_RE.match(str(s)) is not None

Tôi sẽ quan tâm tại sao bạn đang cố gắng tránh thử: ngoại trừ?


1
Một vấn đề về phong cách. Tôi nghĩ rằng "thử / ngoại trừ" chỉ nên được sử dụng với các lỗi thực tế, không phải với luồng chương trình bình thường.
Adam Matan

2
@Udi Pasmon: Python sử dụng khá nhiều thử / ngoại trừ luồng chương trình "bình thường". Ví dụ, mọi iterator dừng lại với một ngoại lệ được nêu ra.
S.Lott

3
-1: Mặc dù gợi ý của bạn trong việc biên dịch regex là đúng, nhưng bạn đã sai khi phê bình Greg ở khía cạnh khác: re.match khớp với đầu chuỗi, vì vậy ^ trong mẫu thực sự là dư thừa. (Điều này khác khi bạn sử dụng re.search).
ThomasH

S.Lott - Đây có được coi là dòng chảy hợp lý trong python? Điều này khác với các ngôn ngữ khác như thế nào? Có lẽ nó đáng giá một câu hỏi riêng biệt.
Adam Matan

1
Việc sử dụng nhiều thử / ngoại trừ của Python đã được đề cập ở đây trên SO. Hãy thử tìm kiếm '[python] ngoại trừ'
S.Lott

4

Tôi phải làm điều này mọi lúc, và tôi có ác cảm nhẹ nhưng thừa nhận không hợp lý khi sử dụng mẫu thử / ngoại trừ. Tôi sử dụng cái này:

all([xi in '1234567890' for xi in x])

Nó không chứa các số âm, vì vậy bạn có thể loại bỏ một dấu trừ (nếu có), sau đó kiểm tra xem kết quả có bao gồm các chữ số từ 0-9 không:

all([xi in '1234567890' for xi in x.replace('-', '', 1)])

Bạn cũng có thể chuyển x sang str () nếu bạn không chắc chắn đầu vào là một chuỗi:

all([xi in '1234567890' for xi in str(x).replace('-', '', 1)])

Có ít nhất hai trường hợp (cạnh?) Khi điều này sụp đổ:

  1. Nó không hoạt động đối với các ký hiệu khoa học và / hoặc hàm mũ khác nhau (ví dụ: 1.2E3, 10 ^ 3, v.v.) - cả hai sẽ trả về Sai. Tôi cũng không nghĩ rằng những câu trả lời khác phù hợp với điều này và thậm chí Python 3.8 cũng có những ý kiến ​​không nhất quán, vì type(1E2)đưa ra <class 'float'>trong khi type(10^2)đưa ra<class 'int'> .
  2. Một đầu vào chuỗi rỗng cho True.

Vì vậy, nó sẽ không hoạt động cho mọi đầu vào có thể, nhưng nếu bạn có thể loại trừ ký hiệu khoa học, ký hiệu số mũ và chuỗi rỗng, thì kiểm tra một dòng OK sẽ trả về Falsenếu x không phải là số nguyên vàTrue nếu x là số nguyên.

Tôi không biết nếu nó là pythonic, nhưng nó là một dòng, và nó tương đối rõ ràng những gì mã làm.


Thử / ngoại trừ có vẻ như đi trên bãi cỏ của ai đó (thử) và sau đó nếu / khi họ nhận thấy và tức giận (ngoại lệ), bạn xin lỗi (xử lý ngoại lệ), trong khi all(xi in '1234567890' for xi in x])mô hình của tôi có vẻ giống như xin phép đi ngang qua bãi cỏ. Tôi không vui mừng khi trở thành người hỏi xin phép, nhưng chúng ta ở đây.
mRotten

3

tôi nghĩ

s.startswith('-') and s[1:].isdigit()

sẽ tốt hơn để viết lại thành:

s.replace('-', '').isdigit()

bởi vì s [1:] cũng tạo ra một chuỗi mới

Nhưng giải pháp tốt hơn nhiều là

s.lstrip('+-').isdigit()

3
Đoán xem cái gì replace? Ngoài ra, điều này sẽ chấp nhận không chính xác 5-2, ví dụ.
Ry-

Sẽ ném IndexError nếus='-'
Chống Trái đất

s = '-'; s.replace ('-', ''). thẩm quyền () -> Sai
Vladyslav Savigan

2

Tôi thực sự thích bài đăng của Shavais, nhưng tôi đã thêm một trường hợp thử nghiệm (& hàm isdigit () tích hợp):

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

và nó liên tục đánh bại thời gian còn lại:

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

sử dụng trăn 2.7 bình thường:

$ python --version
Python 2.7.10

Cả hai trường hợp thử nghiệm mà tôi đã thêm (isInt_loop và isInt_digit) đều vượt qua các trường hợp thử nghiệm chính xác giống nhau (cả hai chỉ chấp nhận số nguyên không dấu), nhưng tôi nghĩ rằng mọi người có thể thông minh hơn với việc sửa đổi triển khai chuỗi (isInt_loop) trái ngược với mã số được xây dựng Hàm (), vì vậy tôi đã bao gồm nó, mặc dù có một chút khác biệt về thời gian thực hiện. (và cả hai phương pháp đánh bại mọi thứ khác rất nhiều, nhưng không xử lý các công cụ bổ sung: "./+/-")

Ngoài ra, tôi cũng thấy thú vị khi lưu ý rằng regex (phương thức isInt num2) đã đánh bại so sánh chuỗi trong cùng một bài kiểm tra đã được Shavais thực hiện vào năm 2012 (hiện tại 2018). Có lẽ các thư viện regex đã được cải thiện?


1

Đây có lẽ là cách đơn giản và pythonic nhất để tiếp cận nó theo ý kiến ​​của tôi. Tôi đã không thấy giải pháp này và về cơ bản nó giống như regex, nhưng không có regex.

def is_int(test):
    import string
    return not (set(test) - set(string.digits))

set(input_string) == set(string.digits)nếu chúng ta bỏ qua '-+ 'lúc bắt đầu và .0, E-1ở cuối.
jfs

1

Đây là một chức năng phân tích cú pháp mà không tăng lỗi. Nó xử lý các trường hợp rõ ràng trả Nonevề lỗi (xử lý các dấu hiệu 2000 '- / +' theo mặc định trên CPython!):

#!/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)

Một số xét nghiệm:

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

Các kết quả:

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

Đối với nhu cầu của bạn, bạn có thể sử dụng:

def int_predicate(number):
     return get_int(number) is not None

1

Tôi đề nghị như sau:

import ast

def is_int(s):
    return isinstance(ast.literal_eval(s), int)

Từ các tài liệu :

Đánh giá một cách an toàn một nút biểu thức hoặc một chuỗi chứa màn hình hiển thị bằng chữ hoặc container của Python. Chuỗi hoặc nút được cung cấp chỉ có thể bao gồm các cấu trúc chữ Python sau: chuỗi, byte, số, bộ dữ liệu, danh sách, ký tự, bộ, booleans và Không có.

Tôi nên lưu ý rằng điều này sẽ đưa ra một ValueErrorngoại lệ khi được gọi chống lại bất cứ thứ gì không cấu thành một chữ Python. Vì câu hỏi yêu cầu giải pháp mà không cần thử / ngoại trừ, tôi có giải pháp loại Kobayashi-Maru cho điều đó:

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

Tôi có một khả năng hoàn toàn không sử dụng int và không nên đưa ra một ngoại lệ trừ khi chuỗi không đại diện cho một số

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

Nó nên hoạt động cho bất kỳ loại chuỗi nào chấp nhận, ký hiệu tích cực, tiêu cực, kỹ thuật ...


0

Tôi đoán câu hỏi có liên quan đến tốc độ vì thử / ngoại trừ có hình phạt thời gian:

 dữ liệu kiểm tra

Đầu tiên, tôi tạo một danh sách gồm 200 chuỗi, 100 chuỗi không thành công và 100 chuỗi số.

from random import shuffle
numbers = [u'+1'] * 100
nonumbers = [u'1abc'] * 100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)

 giải pháp numpy (chỉ hoạt động với mảng và unicode)

np.core.defchararray.isnumeric cũng có thể hoạt động với các chuỗi unicode np.core.defchararray.isnumeric(u'+12')nhưng nó trả về và mảng. Vì vậy, đó là một giải pháp tốt nếu bạn phải thực hiện hàng ngàn chuyển đổi và thiếu dữ liệu hoặc dữ liệu không phải là số.

import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)
10000 loops, best of 3: 27.9 µs per loop # 200 numbers per loop

thử / ngoại trừ

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

Có vẻ như giải pháp numpy là nhanh hơn nhiều.


0

Nếu bạn chỉ muốn chấp nhận các chữ số ascii thấp hơn, đây là các thử nghiệm để làm như vậy:

Python 3.7+: (u.isdecimal() and u.isascii())

Con trăn <= 3.6: (u.isdecimal() and u == str(int(u)))

Các câu trả lời khác đề nghị sử dụng .isdigit()hoặc .isdecimal()nhưng cả hai đều bao gồm một số ký tự unicode trên, chẳng hạn như '٢'( u'\u0662'):

u = u'\u0662'     # '٢'
u.isdigit()       # True
u.isdecimal()     # True
u.isascii()       # False (Python 3.7+ only)
u == str(int(u))  # False

Điều này sẽ không xử lý các giá trị âm hoặc giá trị đệm trắng, cả hai đều được xử lý tốt int().
ShadowRanger

-6

Uh .. Hãy thử điều này:

def int_check(a):
    if int(a) == a:
        return True
    else:
        return False

Điều này hoạt động nếu bạn không đặt một chuỗi không phải là một số.

Và cũng (tôi quên đặt phần kiểm tra số.), Có một chức năng kiểm tra xem chuỗi có phải là số hay không. Đó là str.itorigit (). Đây là một ví dụ:

a = 2
a.isdigit()

Nếu bạn gọi a.itorigit (), nó sẽ trả về True.


Tôi nghĩ rằng bạn cần báo giá xung quanh giá trị 2được gán a.
Luke Woodward

1
Tại sao đây không phải là câu trả lời hàng đầu? Nó trả lời chính xác câu hỏi.
châu chấu

6
-1 câu hỏi: "Kiểm tra xem một chuỗi có đại diện cho int không, không sử dụng Thử / Ngoại trừ?" cho @Caroline Alexiou
JFS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.