ฉันจะตรวจสอบว่าสตริงแสดงถึง int ได้อย่างไรโดยไม่ต้องใช้ลอง / ยกเว้น


466

มีวิธีที่จะบอกว่าใด ๆสตริงหมายถึงจํานวนเต็ม (เช่น'3', '-17'แต่ไม่'3.14'หรือ'asfasfas') โดยไม่ต้องใช้ลอง / ยกเว้นกลไก?

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

23
ทำไมทั้งคู่จึงพยายามทำเช่นนี้ "วิธีที่ยาก" เกิดอะไรขึ้นกับลอง / ยกเว้น
S.Lott

5
ใช่เกิดอะไรขึ้นกับลอง / ยกเว้น ดีกว่าที่จะขอการอภัยมากกว่าการขออนุญาต
mk12

53
ฉันจะถามว่าทำไมสิ่งง่าย ๆ นี้ต้องลอง / ยกเว้น ระบบการยกเว้นเป็นสัตว์ที่มีความซับซ้อน แต่นี่เป็นปัญหาที่ง่าย
Aivar

13
@Aivar หยุดแพร่กระจาย FUD ลอง / ยกเว้นบล็อกเดียวไม่ได้เข้าใกล้ "ซับซ้อน"
Triptych

47
มันไม่ได้เป็น FUD จริงๆ คุณควรเขียนโค้ด 4 บรรทัดอย่างมีประสิทธิภาพโดยคาดหวังว่าจะมีบางอย่างระเบิดจับข้อยกเว้นนั้นและใช้ค่าเริ่มต้นแทนที่จะใช้สายการบินเดียว
andersonvom

คำตอบ:


398

หากคุณรำคาญใจกับการใช้งานtry/exceptทั่วสถานที่โปรดเขียนฟังก์ชันผู้ช่วย:

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

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

มันจะเป็นรหัสเพิ่มเติมทางที่จะครอบคลุมสตริงทั้งหมดที่ Python พิจารณาว่าเป็นจำนวนเต็ม ฉันว่าเพียงแค่ pythonic กับอันนี้


124
ดังนั้น pythonic ในการแก้ปัญหาอย่างง่ายด้วยกลไกที่ซับซ้อน? มีอัลกอริทึมสำหรับตรวจจับฟังก์ชัน int ภายในที่เขียนไว้ว่า "int" - ฉันไม่เห็นว่าทำไมนี่จึงไม่ใช่ฟังก์ชันบูลีน
Aivar

79
@Aivar: ฟังก์ชัน 5 บรรทัดนี้ไม่ใช่กลไกที่ซับซ้อน
Triptych

34
ยกเว้น:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Dannid

5
ฉันเดาว่ามันเป็น "pythonic" ในแง่ที่ว่าถ้า Python คิดว่าสตริงนั้นเป็น int โปรแกรมของคุณก็จะทำงานเช่นกัน ถ้า Python เปลี่ยนโปรแกรมของคุณก็เช่นกันและโดยไม่ต้องเปลี่ยนโค้ดบรรทัดเดียว มีคุณค่าในเรื่องนั้น มันอาจเป็นสิ่งที่ถูกต้องที่จะทำขึ้นอยู่กับสถานการณ์
Shavais

57
ฉันไม่รู้ว่าทำไมนี่คือคำตอบที่ยอมรับหรือมี upvotes มากมายเนื่องจากนี่เป็นสิ่งที่ตรงกันข้ามกับสิ่งที่ OP ขอ
FearlessFuture

755

ด้วยจำนวนเต็มบวกคุณสามารถใช้.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()

6
สิ่งนี้ไม่ได้จัดการ "+17" โดยไม่มีกรณีพิเศษเพิ่มเติม
ไบรอัน Oakley

1
คุณต้องทดสอบทั้งสองกรณี: lambda s: s.isdigit () หรือ (s.startswith ('-') และ s [1:]. isdigit ())
rob

4
@ Roberto: แน่นอนคุณควร! และฉันแน่ใจว่าคุณสามารถทำได้!
SilentGhost

22
หมายเหตุ: u'²'.isdigit()เป็นจริง แต่int(u'²')ก่อให้เกิด ValueError ใช้u.isdecimal()แทน str.isdigit()ขึ้นอยู่กับภาษาใน Python 2
jfs

4
check_int('')จะเพิ่มข้อยกเว้นแทนการส่งคืนFalse
wordbug

97

คุณรู้ว่าฉันได้พบ (และฉันได้ทดสอบสิ่งนี้ซ้ำแล้วซ้ำอีก) ที่ลอง / ยกเว้นทำงานได้ไม่ดีไม่ว่าด้วยเหตุผลใดก็ตาม ฉันมักจะลองทำหลายวิธีและฉันไม่คิดว่าฉันเคยพบวิธีที่ใช้ลอง / ยกเว้นเพื่อให้ได้ผลการทดสอบที่ดีที่สุดในความเป็นจริงดูเหมือนว่าสำหรับฉันแล้ววิธีการเหล่านั้นมักจะออกมาใกล้เคียงกับ เลวร้ายที่สุดถ้าไม่ใช่ที่เลวร้ายที่สุด ไม่ใช่ในทุกกรณี แต่ในหลายกรณี ฉันรู้ว่าผู้คนจำนวนมากพูดว่ามันเป็น "Pythonic" แต่นั่นเป็นพื้นที่หนึ่งที่ฉันมีส่วนร่วมกับพวกเขา สำหรับฉันมันไม่ได้มีประสิทธิภาพมากนักหรือสง่างามมากดังนั้นฉันมักจะใช้เพื่อดักจับและรายงานข้อผิดพลาดเท่านั้น

ฉันจะจับ PHP, perl, ruby, C และแม้แต่ shell ที่ผิดปกติมีฟังก์ชั่นที่ง่ายสำหรับการทดสอบสตริงสำหรับเลขจำนวนเต็ม - hood แต่เนื่องจากความขยันในการตรวจสอบสมมติฐานเหล่านั้นทำให้ฉันสะดุด! เห็นได้ชัดว่าการขาดนี้เป็นโรคทั่วไป

นี่คือการแก้ไขโพสต์ของ 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))

นี่คือผลการเปรียบเทียบประสิทธิภาพ:

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

วิธีการ AC สามารถสแกนมันทีละครั้งและทำได้ ฉันคิดว่าวิธี AC ที่สแกนสตริงครั้งเดียวจะเป็นสิ่งที่ถูกต้อง

แก้ไข:

ฉันได้อัปเดตโค้ดข้างต้นเพื่อให้ทำงานใน Python 3.5 และรวมฟังก์ชัน check_int จากคำตอบที่ได้รับการโหวตมากที่สุดในปัจจุบันและใช้ regex ที่เป็นที่นิยมที่สุดในปัจจุบันที่ฉันสามารถค้นหาเพื่อทดสอบเลขจำนวนเต็ม regex นี้ปฏิเสธสตริงเช่น 'abc 123' ฉันได้เพิ่ม 'abc 123' เป็นค่าทดสอบ

เป็นสิ่งที่น่าสนใจอย่างยิ่งสำหรับฉันที่จะต้องทราบ ณ จุดนี้ว่าไม่มีฟังก์ชั่นที่ทดสอบรวมถึงวิธีลองฟังก์ชั่น check_int ยอดนิยมและ regex ที่นิยมที่สุดสำหรับการทดสอบเลขจำนวนเต็มกลับคำตอบที่ถูกต้องสำหรับทุก ค่าทดสอบ (ดีขึ้นอยู่กับสิ่งที่คุณคิดว่าคำตอบที่ถูกต้องคือดูผลการทดสอบด้านล่าง)

ฟังก์ชั่น int () ฟังก์ชั่นตัดส่วนเศษส่วนของจำนวนจุดลอยตัวและส่งกลับส่วนจำนวนเต็มก่อนทศนิยมยกเว้นในกรณีที่ตัวเลขจุดลอยตัวจะถูกแปลงเป็นสตริงแรก

ฟังก์ชัน check_int () ส่งคืนค่าเท็จสำหรับค่าเช่น 0.0 และ 1.0 (ซึ่งทางเทคนิคเป็นจำนวนเต็ม) และส่งคืนค่าจริงสำหรับค่าเช่น '06'

นี่คือผลการทดสอบปัจจุบัน (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. และ .0 เป็นต้น แต่มันก็ให้ผลตอบแทนจริงสำหรับ '06' เช่นกัน เลือกพิษของคุณฉันเดา


บางทีส่วนหนึ่งของมันมาจากความจริงที่ว่าจำนวนเต็มเป็นบิตเอง ระบบการเขียนโปรแกรมไม่สามารถใช้ความหรูหราในการสมมติว่ามันจะเป็นตัวแทนทศนิยม 0x4df เป็นจำนวนเต็มที่ถูกต้องในบางสถานที่และ 0891 ไม่อยู่ในที่อื่น ฉันกลัวที่จะคิดว่าอะไรจะเกิดขึ้นกับยูนิโค้ดในการตรวจสอบประเภทนี้
PlexQ

3
+1 สำหรับเวลา ฉันยอมรับว่าธุรกิจการยกเว้นทั้งหมดนี้ไม่ได้สง่างามสำหรับคำถามง่ายๆ คุณคาดหวังในการสร้างวิธีการช่วยเหลือสำหรับการดังกล่าวเป็นปัญหาที่พบบ่อย ...
RickyA

9
ฉันรู้ว่ากระทู้นี้นั้นเฉยๆ แต่ +1 สำหรับพิจารณาเวลาทำงาน ความยาวบรรทัดไม่ได้บ่งบอกถึงความซับซ้อนพื้นฐานเสมอไป และแน่ใจว่าลอง / ยกเว้นอาจจะดูง่าย (และอ่านง่ายซึ่งเป็นสิ่งสำคัญมากเกินไป) แต่มันคือการดำเนินการค่าใช้จ่าย ฉันขอยืนยันว่าลำดับชั้นของการตั้งค่าควรมีลักษณะดังนี้: 1. วิธีแก้ปัญหาอย่างชัดเจนในการอ่าน (SilentGhost's) 2. วิธีแก้ปัญหาแบบง่ายต่อการอ่าน (Triptych's) 3. ไม่มีสาม
Eric Humphrey

1
ขอบคุณสำหรับการตรวจสอบ tourough ของคุณเกี่ยวกับหัวข้อที่ดูเหมือนจะไม่สำคัญ ฉันจะไปกับ isInt_str (), pythonic หรือไม่ สิ่งที่ฉันจู้จี้คือฉันไม่พบอะไรเกี่ยวกับความหมายของ v.find ('.. ') นั่นคือไวยากรณ์การค้นหาพิเศษหรือกรณีขอบของสตริงตัวเลขบางชนิดหรือไม่
JackLeEmmerdeur

3
ใช่เก่าไปนิด แต่ก็ยังวิเคราะห์ได้ดีและเกี่ยวข้องจริงๆ ใน Python 3.5 tryมีประสิทธิภาพมากขึ้น: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168
เดฟ

39

str.isdigit() ควรทำเคล็ดลับ

ตัวอย่าง:

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

แก้ไข : ตามที่ @BuzzMoschetti ชี้ให้เห็นวิธีนี้จะล้มเหลวในการลบหมายเลข (เช่น"-23" ) ในกรณีของคุณinput_numสามารถน้อยกว่า 0, ใช้re.sub (regex_search, regex_replace เนื้อหา)ก่อนที่จะใช้str.isdigit () ตัวอย่างเช่น:

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

1
เพราะ -23 ให้ผลเป็นเท็จ
Buzz Moschetti

1
@BuzzMoschetti คุณพูดถูก วิธีที่รวดเร็วในการแก้ไขคือการลบเครื่องหมายลบโดย re.replace (regex_search, regex_replace, เนื้อหา) ก่อนใช้ str.isdigit ()
Catbuilts

27

ใช้นิพจน์ทั่วไป:

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

re.compile()เพื่อประสิทธิภาพที่ดีขึ้นถ้าคุณกำลังทำเช่นนี้มักจะรวบรวมการแสดงออกปกติใช้เพียงครั้งเดียว


19
+1: พบว่าสิ่งนี้มีความซับซ้อนและน่ากลัวเมื่อเปรียบเทียบกับลอง / ยกเว้น
S.Lott

2
ฉันรู้สึกว่านี่เป็นวิธีที่ช้ากว่าและกำหนดเองของโซลูชัน 'isnumeric' ที่เสนอโดย @SilentGhost
เกร็ก

@Greg: เนื่องจาก @SilentGhost ไม่ครอบคลุมสัญญาณอย่างถูกต้องรุ่นนี้ใช้งานได้จริง
S.Lott

1
@ S.Lott: แน่นอนใครก็ตามที่สามารถโพสต์บน SO จะสามารถขยายตัวอย่างของฉันเพื่อให้ครอบคลุมสัญญาณ
SilentGhost

2
การแสดงออกปกติเกี่ยวกับสิ่งที่ซับซ้อนและคลุมเครือมากที่สุดในการดำรงอยู่ฉันพบว่าการตรวจสอบอย่างง่าย ๆ ข้างต้นนั้นชัดเจนยิ่งขึ้นแม้ว่าฉันคิดว่ามันยังน่าเกลียดก็ตาม
PlexQ

18

โซลูชัน 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

4
ฉันจะยอมรับว่าชุดทดสอบของฉันมากเกินไป ฉันชอบที่จะพิสูจน์ว่ารหัสของฉันทำงานเมื่อฉันเขียน แต่คุณคิดว่าฟังก์ชั่น isInteger ของฉันมากไปหรือไม่ ไม่แน่นอน
Bruno Bronosky

1
ฉันเพิ่งได้รับการโหวตโดยไม่มีความคิดเห็น กับคนคืออะไร? ฉันเข้าใจว่าตอนนี้ใช้เวลาเป็นพันปีใช้ "กดไลค์" เป็น "อ่านใบเสร็จ" แต่ตอนนี้พวกเขาใช้คะแนนโหวตเป็นเครื่องหมาย "ไม่ใช่วิธีที่ฉันเลือก" หรือไม่ บางทีพวกเขาอาจไม่ทราบว่าจะลบ 2 คะแนนจากชื่อเสียงของคุณเพื่อโหวตคำตอบ SO / SE ไม่ว่าจะส่งเสริมให้ลงลงคะแนนเพียง แต่เนื่องจากข้อมูลที่ผิดซึ่งในกรณีนี้ฉันหวังว่าคุณจะต้องการแสดงความคิดเห็น
Bruno Bronosky

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

1
is_int ("2") เพิ่ม IndexError
anttikoo

4

วิธีการของ Greg Hewgill หายไปจากองค์ประกอบบางส่วน: "^" นำหน้าเพื่อให้ตรงกับจุดเริ่มต้นของสตริงและรวบรวมอีกครั้งก่อน แต่วิธีการนี้จะช่วยให้คุณหลีกเลี่ยงการลอง: exept:

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

ฉันสนใจว่าทำไมคุณถึงพยายามหลีกเลี่ยง: ยกเว้น?


1
เรื่องของสไตล์ ฉันคิดว่า "ลอง / ยกเว้น" ควรใช้เฉพาะกับข้อผิดพลาดจริงไม่ใช่กับโฟลว์โปรแกรมปกติ
Adam Matan

2
@Udi Pasmon: Python ใช้งานค่อนข้างหนักในการลอง / ยกเว้นการไหลของโปรแกรม "ปกติ" ตัวอย่างเช่นตัววนซ้ำทุกตัวหยุดด้วยข้อยกเว้นที่ยกขึ้น
S.Lott

3
-1: แม้ว่าคำแนะนำของคุณในการรวบรวม regex นั้นถูกต้อง แต่คุณผิดในการวิพากษ์วิจารณ์ Greg ในด้านอื่น ๆ : re.match จับคู่กับจุดเริ่มต้นของสตริงดังนั้น ^ ในรูปแบบนั้นซ้ำซ้อนจริง ๆ (สิ่งนี้แตกต่างเมื่อคุณใช้ re.search)
ThomasH

S.Lott - นี่ถือว่าเป็นการไหลที่สมเหตุสมผลในไพ ธ อนไหม สิ่งนี้แตกต่างจากภาษาอื่น ๆ อย่างไร บางทีมันก็คุ้มค่ากับคำถามที่แยกต่างหาก
Adam Matan

1
การทดลองใช้ / การใช้ Python อย่างหนักได้ถูกกล่าวถึงในที่นี้ใน SO ลองค้นหา '[python] ยกเว้น'
S.Lott

4

ฉันต้องทำเช่นนี้ตลอดเวลาและฉันมีความเกลียดชังที่ไม่รุนแรง แต่ไม่เป็นที่ยอมรับในการใช้รูปแบบลอง / ยกเว้น ฉันใช้สิ่งนี้:

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

ไม่รองรับจำนวนลบดังนั้นคุณสามารถตัดเครื่องหมายลบหนึ่งเครื่องหมาย (ถ้ามี) แล้วตรวจสอบว่าผลลัพธ์ประกอบด้วยตัวเลขตั้งแต่ 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)])

มีอย่างน้อยสองกรณี (ขอบ?) ซึ่งสิ่งนี้แตกสลาย:

  1. มันใช้ไม่ได้กับสัญลักษณ์ทางวิทยาศาสตร์และ / หรือสัญลักษณ์ต่าง ๆ (เช่น 1.2E3, 10 ^ 3, ฯลฯ ) - ทั้งคู่จะคืนค่าเป็นเท็จ ฉันไม่คิดว่าคำตอบอื่น ๆ พักนี้อย่างใดอย่างหนึ่งและแม้กระทั่งงูหลาม 3.8 มีความคิดเห็นที่ไม่สอดคล้องกันเนื่องจากtype(1E2)จะช่วยให้<class 'float'>ในขณะที่ช่วยให้type(10^2)<class 'int'>
  2. การป้อนสตริงที่ว่างเปล่าให้ True

ดังนั้นจะไม่ทำงานสำหรับทุกอินพุตที่เป็นไปได้ แต่ถ้าคุณสามารถยกเว้นเครื่องหมายทางวิทยาศาสตร์, สัญลักษณ์เอ็กซ์โพเนนเชียลและสตริงว่างมันเป็นการตรวจสอบหนึ่งบรรทัดที่ตกลงว่าส่งคืนFalseถ้า x ไม่ใช่จำนวนเต็มและTrueถ้า x เป็นจำนวนเต็ม

ฉันไม่รู้ว่ามันเป็น pythonic หรือไม่ แต่เป็นหนึ่งบรรทัดและค่อนข้างชัดเจนว่าโค้ดทำอะไร


ลอง / ยกเว้นดูเหมือนว่ากำลังเดินอยู่บนสนามหญ้าของใครบางคน (ลอง) และถ้า / เมื่อพวกเขาสังเกตเห็นและโกรธ (ยกเว้น) คุณต้องขออภัย (จัดการกับข้อยกเว้น) ในขณะที่all(xi in '1234567890' for xi in x])รูปแบบของฉันดูเหมือนจะขออนุญาตให้เดินข้ามสนามหญ้า ฉันไม่ได้ตื่นเต้นที่ได้เป็นผู้ขออนุญาต แต่เราอยู่ที่นี่
mRotten

3

ฉันคิด

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

จะดีกว่าถ้าเขียนใหม่เป็น:

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

เพราะ s [1:] ยังสร้างสตริงใหม่

แต่ทางออกที่ดีกว่าก็คือ

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

3
คาดเดาสิ่งที่replaceทำ เช่นนี้จะยอมรับอย่างไม่ถูกต้อง5-2เช่น
Ry-

จะโยนดัชนีผิดพลาดถ้าs='-'
Anti Earth

s = '-'; s.replace ('-', '') .isdigit () -> False
Vladyslav Savchenko

2

ฉันชอบโพสต์ของ Shavais จริงๆ แต่ฉันได้เพิ่มอีกหนึ่งกรณีทดสอบ (& ฟังก์ชัน 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 --version
Python 2.7.10

ทั้งสองกรณีทดสอบที่ฉันเพิ่ม (isInt_loop และ isInt_digit) ผ่านกรณีทดสอบเดียวกันที่แน่นอน (ทั้งคู่ยอมรับเฉพาะจำนวนเต็มที่ไม่ได้ลงนาม) แต่ฉันคิดว่าผู้คนจะฉลาดกว่าด้วยการปรับเปลี่ยนการใช้สตริง (isInt_loop) ตรงข้ามกับ built in isdigit () ฟังก์ชั่นดังนั้นฉันจึงรวมไว้แม้ว่าจะมีความแตกต่างเล็กน้อยในเวลาดำเนินการ (และทั้งสองวิธีเอาชนะทุกอย่างเป็นอย่างมาก แต่อย่าจัดการกับสิ่งพิเศษ: "./+/-")

นอกจากนี้ฉันพบว่ามันน่าสนใจที่จะทราบว่า regex (isInt_re2 วิธี) เอาชนะการเปรียบเทียบสตริงในการทดสอบเดียวกันที่ดำเนินการโดย Shavais ในปี 2012 (ปัจจุบัน 2018) อาจปรับปรุงไลบรารี regex หรือไม่


1

นี่อาจเป็นวิธีที่ตรงไปตรงมาและไพเราะที่สุดในความคิดของฉัน ฉันไม่เห็นวิธีแก้ปัญหานี้และมันก็เหมือนกับ regex แต่ไม่มี regex

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

set(input_string) == set(string.digits)ถ้าเราข้ามไป'-+ 'ที่จุดเริ่มต้นและ.0, E-1ในตอนท้าย
jfs

1

นี่คือฟังก์ชันที่แยกวิเคราะห์โดยไม่เพิ่มข้อผิดพลาด มันจัดการกรณีที่เห็นได้ชัดผลตอบแทนNoneจากความล้มเหลว (จัดการได้ถึง 2000 '- / +' สัญญาณตามค่าเริ่มต้นใน 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)

การทดสอบบางอย่าง:

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

1

ฉันขอแนะนำดังต่อไปนี้:

import ast

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

จากเอกสาร :

ประเมินโหนดนิพจน์หรือสตริงที่มีการแสดงตัวอักษรหรือคอนเทนเนอร์ของ Python อย่างปลอดภัย สตริงหรือโหนดที่ระบุอาจประกอบด้วยโครงสร้างตัวอักษร Python ดังต่อไปนี้เท่านั้น: สตริง, ไบต์, ตัวเลข, สิ่งอันดับ, รายการ, dicts, ชุด, booleans และไม่มี

ฉันควรทราบว่าสิ่งนี้จะทำให้เกิดValueErrorข้อยกเว้นเมื่อมีการเรียกร้องสิ่งใดก็ตามที่ไม่ได้เป็นตัวอักษร Python เนื่องจากคำถามถามหาทางออกโดยไม่ลอง / ยกเว้นฉันมีวิธีแก้ปัญหาแบบ Kobayashi-Maru สำหรับสิ่งนั้น:

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

ฉันมีความเป็นไปได้หนึ่งอย่างที่ไม่ได้ใช้ int เลยและไม่ควรเพิ่มข้อยกเว้นเว้นแต่สตริงจะไม่แสดงตัวเลข

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

มันควรใช้กับสตริงชนิดใดก็ได้ที่ลอยยอมรับ, เป็นลบ, เป็นเครื่องหมายทางวิศวกรรม ...


0

ฉันเดาว่าคำถามนั้นเกี่ยวข้องกับความเร็วตั้งแต่การลอง / ยกเว้นมีการปรับเวลา:

 ข้อมูลการทดสอบ

ก่อนอื่นฉันสร้างรายการ 200 สตริง 100 สตริงที่ล้มเหลวและ 100 ตัวเลข

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

 วิธีการแก้ปัญหา numpy (ใช้งานได้กับอาร์เรย์และ unicode เท่านั้น)

np.core.defchararray.isnumeric ยังสามารถทำงานกับสตริง unicode ได้np.core.defchararray.isnumeric(u'+12')แต่มันจะส่งคืนและเรียงลำดับ ดังนั้นจึงเป็นทางออกที่ดีหากคุณต้องทำหลายพัน Conversion และไม่มีข้อมูลหรือข้อมูลที่ไม่ใช่ตัวเลข

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 นั้นเร็วกว่ามาก


0

หากคุณต้องการที่จะยอมรับตัวเลขที่ต่ำกว่า 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

นี้จะไม่จัดการกับค่าลบหรือค่าเบาะ whitespaced int()ซึ่งทั้งสองได้รับการจัดการโดยเพียงแค่ปรับ
ShadowRanger

-6

เอ่อ .. ลองดูสิ:

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

วิธีนี้ใช้ได้ผลถ้าคุณไม่ใส่สตริงที่ไม่ใช่ตัวเลข

และ (ฉันลืมใส่ส่วนตรวจสอบตัวเลข) มีฟังก์ชั่นตรวจสอบว่าสตริงเป็นตัวเลขหรือไม่ มันคือ str.isdigit () นี่คือตัวอย่าง:

a = 2
a.isdigit()

หากคุณโทร a.isdigit () ระบบจะส่งคืน True


ผมคิดว่าคุณต้องคำพูดรอบค่ามอบหมายให้2 a
ลุควู้ดเวิร์ด

1
ทำไมคำตอบนี้ไม่ได้ มันตอบคำถามอย่างแน่นอน
ตั๊กแตน

6
-1 คำถาม: "ตรวจสอบว่าสตริงแสดงถึง int โดยไม่ต้องใช้ลอง / ยกเว้น?" สำหรับ @Caroline Alexiou
jfs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.