try / except를 사용하지 않고 문자열이 int를 나타내는 지 어떻게 확인할 수 있습니까?


466

여부를 알 수있는 방법이 있나요 문자열 (예를 들어, 정수를 나타내고 '3', '-17'하지만 '3.14''asfasfas'메커니즘을 제외 / 시도를 사용하지 않고)는?

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

23
왜 둘 다 "어려운 길"을하려고합니까? try / except의 문제점은 무엇입니까?
S.Lott

5
예, 시도 / 제외의 문제점은 무엇입니까? 허가보다는 용서를 구하는 것이 좋습니다.
mk12

53
이 간단한 일에 시도 / 제외가 필요한 이유는 무엇입니까? 예외 시스템은 복잡한 짐승이지만 간단한 문제입니다.
Aivar

13
@Aivar는 FUD 확산을 중지합니다. 단일 try / except 블록은 "복잡한"접근하지 않습니다.
Triptych

47
그러나 실제로는 FUD가 아닙니다. 하나의 라이너를 사용하는 대신 4 줄의 코드를 효과적으로 작성하여 무언가를 날려 버릴 것으로 예상하고 예외를 포착하고 기본값을 수행합니다.
andersonvom

답변:


398

try/excepts 를 사용하는 것이 정말 짜증나는 경우 도우미 함수를 작성하십시오.

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

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

파이썬이 정수로 간주하는 모든 문자열을 정확하게 다루기 위해 더 많은 코드가 될 것입니다. 나는 이것에 대해 pythonic이라고 말합니다.


124
복잡한 메커니즘으로 간단한 문제를 해결하는 것은 비현실적입니까? int가 작성한 함수 "int"를 감지하는 알고리즘이 있습니다. 이것이 부울 함수로 노출되지 않는 이유는 알 수 없습니다.
Aivar

79
@Aivar :이 5 라인 기능은 복잡한 메커니즘이 아닙니다.
Triptych

34
예외 :>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Dannid

5
파이썬이 문자열을 정수라고 생각하면 프로그램도 마찬가지라는 의미에서 "파이 토닉"이라고 생각합니다. 파이썬이 변경되면, 한 줄의 코드를 변경하지 않고 프로그램도 변경됩니다. 거기에는 약간의 가치가 있습니다. 상황에 따라해야 할 수도 있습니다.
Shavais

57
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"을 처리하지 않습니다.
Bryan Oakley

1
두 경우 모두를 테스트해야합니다. lambda s : s.isdigit () 또는 (s.startswith ( '-') and s [1 :]. isdigit ())
rob

4
@Roberto : 물론해야합니다! 그리고 당신이 그렇게 할 수 있다고 확신합니다!
SilentGhost

22
참고 : u'²'.isdigit()true이지만 int(u'²')ValueError가 발생합니다. u.isdecimal()대신 사용하십시오 . str.isdigit()파이썬 2에서 로케일에 의존합니다.
jfs

4
check_int('')반환하는 대신 예외를 제기합니다False
wordbug

97

시도 / 제외가 어떤 이유로 든 잘 수행되지 않는 것을 발견했습니다 (그리고 이것을 반복해서 테스트했습니다). 나는 종종 여러 가지 일을 시도하고, 시도 / 제외를 사용하여 테스트 된 것 중 가장 좋은 것을 수행하는 방법을 찾지 못했다고 생각합니다. 실제로 그 방법은 일반적으로 최악이 아니라면 최악입니다. 모든 경우가 아니라 많은 경우에 해당됩니다. 나는 많은 사람들이 그것이 "Pythonic"방식이라고 말하지만, 그것은 내가 그들과 함께하는 하나의 영역입니다. 나에게 그것은 성능이 우수하지도 않고 우아하지도 않으므로 오류 트래핑 및보고에만 사용하는 경향이 있습니다.

PHP, perl, ruby, C 및 심지어 괴물 껍질조차도 문자열을 정수로 테스트하는 간단한 기능을 가지고 있지만 그 가정을 검증하는 데 상당한주의를 기울여 나를 혼란스럽게 만들었습니다! 분명히이 부족은 흔한 질병입니다.

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 방법이 올바른 일이라고 생각합니다.

편집하다:

파이썬 3.5에서 작동하고 현재 가장 많이 투표 된 답변에서 check_int 함수를 포함하고 정수 테스트를 위해 찾을 수있는 가장 인기있는 정규식을 사용하도록 위의 코드를 업데이트했습니다. 이 정규 표현식은 'abc 123'과 같은 문자열을 거부합니다. 테스트 값으로 'abc 123'을 추가했습니다.

이 시점에서 try 메소드, 인기있는 check_int 함수 및 정수를 테스트하기 위해 가장 인기있는 정규 표현식을 포함하여 테스트 된 함수 중 어느 것도 함수에 대한 정답을 반환하지 않습니다. 테스트 값 (정답이 무엇인지 생각에 따라 아래의 테스트 결과 참조).

내장 int () 함수는 부동 소수점 숫자가 문자열로 먼저 변환되지 않는 한 부동 소수점 숫자의 소수 부분을 자동으로 자르고 소수 앞에 정수 부분을 리턴합니다.

check_int () 함수는 0.0 및 1.0 (기술적으로 정수)과 같은 값에 대해서는 false를 반환하고 '06'과 같은 값에 대해서는 true를 반환합니다.

현재 (Python 3.5) 테스트 결과는 다음과 같습니다.

                  isInt_try |       isInt_str       |       isInt_re        |       isInt_re2       |   check_int   |
    0               True    |               True    |               True    |               True    |       True    |
    1               True    |               True    |               True    |               True    |       True    |
    -1              True    |               True    |               True    |               True    |       True    |
    1.0             True    |               True    |               False   |               False   |       False   |
    -1.0            True    |               True    |               False   |               False   |       False   |
    '0'             True    |               True    |               True    |               True    |       True    |
    '0.'            False   |               True    |               False   |               False   |       False   |
    '0.0'           False   |               True    |               False   |               False   |       False   |
    '1'             True    |               True    |               True    |               True    |       True    |
    '-1'            True    |               True    |               True    |               True    |       True    |
    '+1'            True    |               True    |               True    |               True    |       True    |
    '1.0'           False   |               True    |               False   |               False   |       False   |
    '-1.0'          False   |               True    |               False   |               False   |       False   |
    '+1.0'          False   |               True    |               False   |               False   |       False   |
    '06'            True    |               True    |               False   |               False   |       True    |
    'abc 123'       False   |               False   |               False   |               False   |       False   |
    1.1             True    |               False   |               False   |               False   |       False   |
    -1.1            True    |               False   |               False   |               False   |       False   |
    '1.1'           False   |               False   |               False   |               False   |       False   |
    '-1.1'          False   |               False   |               False   |               False   |       False   |
    '+1.1'          False   |               False   |               False   |               False   |       False   |
    '1.1.1'         False   |               False   |               False   |               False   |       False   |
    '1.1.0'         False   |               False   |               False   |               False   |       False   |
    '1.0.1'         False   |               False   |               False   |               False   |       False   |
    '1.0.0'         False   |               False   |               False   |               False   |       False   |
    '1.0.'          False   |               False   |               False   |               False   |       False   |
    '1..0'          False   |               False   |               False   |               False   |       False   |
    '1..'           False   |               False   |               False   |               False   |       False   |
    '0.0.'          False   |               False   |               False   |               False   |       False   |
    '0..0'          False   |               False   |               False   |               False   |       False   |
    '0..'           False   |               False   |               False   |               False   |       False   |
    'one'           False   |               False   |               False   |               False   |       False   |
    <obj..>         False   |               False   |               False   |               False   |       False   |
    (1, 2, 3)       False   |               False   |               False   |               False   |       False   |
    [1, 2, 3]       False   |               False   |               False   |               False   |       False   |
    {'one': 'two'}  False   |               False   |               False   |               False   |       False   |
    ' 0 '           True    |               True    |               True    |               True    |       False   |
    ' 0.'           False   |               True    |               False   |               False   |       False   |
    ' .0'           False   |               False   |               False   |               False   |       False   |
    '.01 '          False   |               False   |               False   |               False   |       False   |

지금은이 기능을 추가하려고했습니다.

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

check_int (0.3486)와 거의 동일하게 작동하며 1.0 및 0.0 및 +1.0 및 0과 0 등의 값에 대해서는 true를 반환합니다. 그러나 '06'에 대해서도 true를 반환합니다. 독을 골라 봐


아마도 그중 일부는 정수가 약간 임의적이라는 사실에서 비롯된 것입니다. 프로그래밍 시스템은 항상 십진 표현이라고 가정 할 수 없습니다. 0x4df는 일부 지역에서 유효한 정수이며 0891은 다른 곳에서는 유효하지 않습니다. 이런 종류의 검사에서 유니 코드가 주어지면 어떻게 될지 생각하는 것이 무섭습니다.
PlexQ

3
타이밍 +1 나는이 전체 예외 사업이 그러한 간단한 질문에 대해 실제로 우아하지 않다는 것에 동의합니다. 이러한 일반적인 문제에 대한 도우미 메소드 빌드가 필요합니다.
RickyA

9
이 스레드는 기본적으로 휴면 상태이지만 런타임을 고려하면 +1입니다. 줄 길이가 항상 기본 복잡성을 나타내는 것은 아닙니다. 그리고 확인하는 힘 모습 간단한 제외한 시도 /하지만 (그리고 너무 중요하다, 쉽게 읽기) 입니다 비용이 많이 드는 작업. 기본 설정 계층 구조는 항상 다음과 같아야한다고 주장합니다. 1. 읽기 쉬운 명시 적 솔루션 (SilentGhost 's). 2. 읽기 쉬운 암시 적 솔루션 (Triptych). 3. 셋이 없습니다.
Eric Humphrey

1
겉보기에 중요하지 않은 주제에 관한 둘러보기 조사에 감사드립니다. pythonic 여부에 관계없이 isInt_str ()을 사용하겠습니다. 잔소리하는 것은 v.find ( '..')의 의미에 대해 아무것도 찾지 못했다는 것입니다. 특별한 종류의 구문 찾기 또는 숫자 문자열의 대소 문자입니까?
JackLeEmmerdeur 2016 년

3
예, 약간 오래되었지만 여전히 훌륭하고 관련성이 높은 분석입니다. 파이썬 3.5에서는 tryisInt_try : 0.6552 / isInt_str : 0.6396 / isInt_re : 1.0296 / isInt_re2 : 0.5168가 더 효율적입니다.
Dave

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이 false를 생성하기 때문입니다.
Buzz Moschetti 2016 년

1
@BuzzMoschetti 당신이 맞아요. str.isdigit ()를 적용하기 전에 re.replace (regex_search, regex_replace, contents)로 빼기 부호를 제거하는 빠른 방법입니다.
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
나는 이것이 본질적으로 @SilentGhost가 제공하는 '이성질체'솔루션의 느리고 사용자 정의 버전이라고 생각합니다.
Greg Greg

@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의 접근 방식에는 몇 가지 구성 요소가 누락되었습니다. 문자열의 시작 부분에만 일치하는 선행 "^"및 사전 컴파일. 그러나이 방법을 사용하면 시도를 피할 수 있습니다.

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 : 파이썬은 "정상적인"프로그램 흐름을 위해 try / except를 상당히 많이 사용합니다. 예를 들어, 모든 반복자는 예외 발생으로 중지됩니다.
S.Lott

3
-1 : 정규 표현식을 컴파일 할 때의 힌트는 옳지 만 Greg는 다른 측면에서 비판하는 데 잘못되었습니다. 재시작 은 문자열 의 시작 부분 과 일치 하므로 패턴의 ^는 실제로 중복됩니다. (re.search를 사용할 때는 다릅니다).
ThomasH

S.Lott-이것은 파이썬에서 합리적인 흐름으로 간주됩니까? 이것이 다른 언어와 어떻게 다릅니 까? 아마도 별도의 질문의 가치가 있습니다.
Adam Matan

1
파이썬에서 try / except를 많이 사용하는 것은 여기에서 다루었습니다. '[python] except'를 검색해보세요
S.Lott

4

나는 항상이 작업을 수행해야하며 try / except 패턴을 사용하는 것에 대해 온화하지만 명백하게 비합리적인 혐오감을 가지고 있습니다. 나는 이것을 사용한다 :

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 등)에서는 작동하지 않습니다. 둘 다 False를 반환합니다. 나는 다른 대답이 이것을 수용했다고 생각하지 않으며, 파이썬 3.8조차도 type(1E2)주는 <class 'float'>반면 type(10^2)제공하기 때문에 의견이 일치하지 않습니다 <class 'int'>.
  2. 빈 문자열 입력은 True를 제공합니다.

따라서 가능한 모든 입력에 대해 작동 하지는 않지만 과학 표기법, 지수 표기법 및 빈 문자열을 제외 할 수 False있으면 x가 정수가 아니고 x가 정수인지 를 반환하는 OK 한 줄 검사입니다 True.

파이썬이 아닌지 모르겠지만 한 줄이며 코드의 기능이 상대적으로 명확합니다.


시도 / 제외는 누군가의 잔디밭 위를 걷는 것처럼 보이고 (시도) 그들이 눈치 채고 화를 내면 (예외) 당신은 사과하고 (예외 처리), 내 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-

다음과 같은 경우 IndexError가 발생합니다.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)는 모두 동일한 테스트 사례를 통과하지만 (모두 부호없는 정수만 허용 함) 내장 isdigit과 반대로 문자열 구현 (isInt_loop)을 수정하면 사람들이 더 영리 할 수 ​​있다고 생각했습니다. () 함수이므로 실행 시간에 약간의 차이가 있지만 포함 시켰습니다. (두 방법 모두 다른 모든 것을 능가하지만 여분의 것을 처리하지 마십시오 : "./+/-")

또한 정규식 (isInt_re2 방법)이 2012 년 (현재 2018) Shavais가 수행 한 것과 동일한 테스트에서 문자열 비교를 능가한다는 점에 주목하는 것이 흥미로 웠습니다. 정규식 라이브러리가 개선되었을 수 있습니까?


1

이것은 아마도 내 의견으로는 접근하는 가장 간단하고 파이썬적인 방법 일 것입니다. 이 솔루션을 보지 못했지만 기본적으로 정규식과 동일하지만 정규식이 없습니다.

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실패시 리턴 리턴 (CPython에서 기본적으로 최대 2000 개의 '-/ +'부호 처리)을 처리합니다.

#!/usr/bin/env python

def get_int(number):
    splits = number.split('.')
    if len(splits) > 2:
        # too many splits
        return None
    if len(splits) == 2 and splits[1]:
        # handle decimal part recursively :-)
        if get_int(splits[1]) != 0:
            return None

    int_part = splits[0].lstrip("+")
    if int_part.startswith('-'):
        # handle minus sign recursively :-)
        return get_int(int_part[1:]) * -1
    # successful 'and' returns last truth-y value (cast is always valid)
    return int_part.isdigit() and int(int_part)

일부 테스트 :

tests = ["0", "0.0", "0.1", "1", "1.1", "1.0", "-1", "-1.1", "-1.0", "-0", "--0", "---3", '.3', '--3.', "+13", "+-1.00", "--+123", "-0.000"]

for t in tests:
    print "get_int(%s) = %s" % (t, get_int(str(t)))

결과 :

get_int(0) = 0
get_int(0.0) = 0
get_int(0.1) = None
get_int(1) = 1
get_int(1.1) = None
get_int(1.0) = 1
get_int(-1) = -1
get_int(-1.1) = None
get_int(-1.0) = -1
get_int(-0) = 0
get_int(--0) = 0
get_int(---3) = -3
get_int(.3) = None
get_int(--3.) = 3
get_int(+13) = 13
get_int(+-1.00) = -1
get_int(--+123) = 123
get_int(-0.000) = 0

필요에 따라 다음을 사용할 수 있습니다.

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

1

나는 다음을 제안한다.

import ast

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

로부터 문서 :

파이썬 리터럴 또는 컨테이너 디스플레이를 포함하는 표현식 노드 또는 문자열을 안전하게 평가하십시오. 제공된 문자열 또는 노드는 문자열, 바이트, 숫자, 튜플, 목록, dicts, set, booleans 및 None과 같은 Python 리터럴 구조로만 구성 될 수 있습니다.

ValueError파이썬 리터럴을 구성하지 않는 것에 대해 호출 하면 예외가 발생합니다. 질문은 시도 / 제외가없는 솔루션을 요구했기 때문에 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

float가 허용하는 모든 종류의 문자열에 대해 작동해야합니다. 긍정적, 부정적, 공학적 표기법 ...


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 솔루션 (배열 및 유니 코드에서만 작동)

np.core.defchararray.isnumeric은 유니 코드 문자열에도 사용할 수 np.core.defchararray.isnumeric(u'+12')있지만 반환하고 배열합니다. 따라서 수천 번의 변환을 수행해야하고 누락 된 데이터 또는 숫자가 아닌 데이터가있는 경우 좋은 솔루션입니다.

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

시도 / 제외

def check_num(s):
  try:
    int(s)
    return True
  except:
    return False

def check_list(l):
  return [check_num(e) for e in l]

%timeit check_list(testlist)
1000 loops, best of 3: 217 µs per loop # 200 numbers per loop

numpy 솔루션이 훨씬 빠릅니다.


0

낮은 ASCII 숫자 만 허용하려면 다음을 수행하십시오.

파이썬 3.7 이상 : (u.isdecimal() and u.isascii())

파이썬 <= 3.6 : (u.isdecimal() and u == str(int(u)))

다른 답변은 .isdigit()또는을 사용하는 것이 .isdecimal()좋지만 둘 다'٢' ( u'\u0662') 와 같은 일부 상위 유니 코드 문자를 포함합니다 .

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

음수 값이나 공백으로 채워진 값은 처리하지 않으며 둘 다 잘 처리됩니다 int().
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.
Luke Woodward

1
이 최고 답변이 아닌 이유는 무엇입니까? 질문에 정확하게 대답합니다.
메뚜기

6
-1 질문 : " 문자열이 시도 / 제외를 사용하지 않고 int를 나타내는 지 확인 하시겠습니까?" @Caroline Alexiou의 경우
jfs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.