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

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

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



답변

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

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

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

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


답변

양의 정수로 다음을 사용할 수 있습니다 .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()


답변

시도 / 제외가 어떤 이유로 든 잘 수행되지 않는 것을 발견했습니다 (그리고 이것을 반복해서 테스트했습니다). 나는 종종 여러 가지 일을 시도하고, 시도 / 제외를 사용하여 테스트 된 것 중 가장 좋은 것을 수행하는 방법을 찾지 못했다고 생각합니다. 실제로 그 방법은 일반적으로 최악이 아니라면 최악입니다. 모든 경우가 아니라 많은 경우에 해당됩니다. 나는 많은 사람들이 그것이 “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를 반환합니다. 독을 골라 봐


답변

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


답변

정규식을 사용하십시오.

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


답변

적절한 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


답변

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