문자열이 숫자 (부동)인지 어떻게 확인합니까?


1607

파이썬에서 문자열을 숫자로 나타낼 수 있는지 확인하는 가장 좋은 방법은 무엇입니까?

현재 내가 가지고있는 기능은 다음과 같습니다.

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

추악하고 느릴뿐만 아니라 어색한 것 같습니다. 그러나 float주 함수를 호출하는 것이 더 나쁘기 때문에 더 좋은 방법을 찾지 못했습니다 .


61
현재 솔루션에 어떤 문제가 있습니까? 짧고 빠르며 읽을 수 있습니다.
Colonic Panic

5
그리고 당신은 단지 참 또는 거짓을 반환 할 필요가 없습니다. 대신 적절하게 수정 된 값을 반환 할 수 있습니다. 예를 들어, 숫자를 사용하지 않고 따옴표로 묶을 수 있습니다.
Thruston

7
성공적인 변환의 경우 float (s)의 결과를 반환하는 것이 더 좋지 않습니까? 당신은 여전히 ​​성공 여부를 확인하고 (결과는 False입니다) 실제로 변환을해야합니다. 어쨌든 원할 것입니다.
Jiminion

8
이 질문은 더 오래되었지만 이것이 EAFP 로 문서화 된 우아한 방법이라고 말하고 싶었 습니다 . 아마도 이런 종류의 문제에 가장 적합한 해결책 일 것입니다.
thiruvenkadam

7
float (s) 결과 또는 실패시 없음을 반환 하지 마십시오 . 그렇다면 x = float('0.00'); if x: use_float(x);코드에 버그가 생겼을 때 사용하십시오 . 진실한 가치는이 함수 None들이 처음에 돌아 오는 것이 아니라 예외를 일으키는 이유 입니다. 더 나은 해결책은 유틸리티 기능을 피하고 try catch사용하고자 할 때 플로팅 호출을 둘러싸는 것입니다.
ovangle

답변:


698

추악하고 느릴뿐만 아니라

나는 둘 다 논쟁 할 것이다.

정규식이나 다른 문자열 구문 분석 방법은 더 느리고 느립니다.

위의 것보다 많은 것이 빠를 지 확실하지 않습니다. 함수를 호출하고 반환합니다. 스택 프레임을 광범위하게 검색하지 않고 가장 일반적인 예외가 발생하기 때문에 Try / Catch는 많은 오버 헤드를 발생시키지 않습니다.

문제는 모든 숫자 변환 함수에 두 가지 종류의 결과가 있다는 것입니다

  • 숫자가 유효하면 숫자
  • 유효한 번호를 구문 분석 할 수 없음을 표시하는 상태 코드 (예 : errno를 통한) 또는 예외입니다.

예를 들어 C는 여러 가지 방법으로 해킹합니다. 파이썬은 그것을 명확하고 명시 적으로 설명합니다.

이 작업을 수행하는 코드가 완벽하다고 생각합니다.


21
나는 코드가 완벽하다 생각하지 않습니다 (그러나 나는 그것이 매우 가까운 생각) : 그것을 넣어하는 것이 더 일반적이다 에만 의 부분은 "테스트"하고 try나는를 둘 것, 그래서 절 return True에서 else의 절 try. 그 이유 중 하나는 문제의 코드를 사용하여 검토해야한다면 try조항 의 두 번째 문 이 ValueError를 발생시킬 수 없는지 확인해야한다는 것입니다 . 그러나 왜 필요하지 않을 때 왜 사용합니까?
Eric O Lebigot

4
그 대답은 설득력이있는 것처럼 보이지만 왜 기본 제공되지 않는지 궁금합니다. 이것을 복사하여 어떤 경우에도 사용하겠습니다.
Sage

9
얼마나 끔찍한. 숫자 무엇인지 신경 쓰지 않는다면 어떻습니까? 한 줄 대신에 IsNumeric()try / catch 또는 try / catch를 포장하는 다른 것으로 끝납니다. Ugh
기본

6
if is_number(s): x = float(x) else: // fail와 동일한 수의 코드 행이 있기 때문에 '바로 사용하지 않음'이 제공되지 않습니다 try: x = float(x) catch TypeError: # fail. 이 유틸리티 기능은 완전히 불필요한 추상화입니다.
ovangle

12
그러나 추상화는 라이브러리의 핵심입니다. 어떤 언어로든 'isNumber'함수를 사용하면 if 문으로 직접 작성할 수 있고 try-catch 블록에 의존하는 훨씬 더 읽기 쉽고 유지 관리 가능한 코드를 가질 수 있기 때문에 엄청난 도움이됩니다. 또한 둘 이상의 클래스 / 모듈에서 코드를 두 번 이상 사용해야하는 경우 내장 함수보다 많은 코드 줄을 사용했습니다.
JamEngulfer 11

1612

부동 소수점 대신 (양수, 부호없는) 정수를 파싱하려는 경우 isdigit()문자열 객체에 함수를 사용할 수 있습니다 .

>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False

문자열 메소드- isdigit(): Python2 , Python3

유니 코드 문자열에는 유니 코드에 익숙하지 않은 것도 있습니다. 십진수 / 십진수입니다


232
그것은 부정적인면에서도 부정적입니다
intrepion

22
도 지수 함수 실패 : '1e3'.isdigit를 () -> 거짓
SSC

35
Number! = Digit이지만 문자열에 정수가 포함되어 있는지 테스트하는 방법을 찾는 사람들은이 질문을 우연히 발견 할 수 있으며 isDigit 접근법은 응용 프로그램에 완벽하게 적합 할 수 있습니다.
Adam Parkin

8
@AdamParkin : isdigit()그리고 int()유니 코드 문자의 경우 정수가 무엇인지에 대한 의견이 다릅니다 u'\u00b9': u'¹'.isdigit()is is Truebut int(u'¹')ValueError.
jfs

6
+1 : isdigit ()는 OP가 찾고 있던 것이 아닐 수도 있지만 정확히 내가 원하는 것입니다. 이 답변과 방법이 모든 유형의 숫자를 다루지는 않지만, 정확성에 대한 주장과는 달리 여전히 관련성이 높습니다. "Number! = Digit"인 반면, 숫자는 여전히 숫자의 하위 세트입니다. 특히 양수, 음수가 아니고 1-10을 사용하는 숫자입니다. 또한이 방법은 문자열이 숫자 ID인지 여부를 검사하려는 경우 특히 유용하고 간략합니다. 이는 종종 방금 설명한 숫자의 하위 집합에 해당합니다.
Justin Johnson

161

TL; DR 가장 좋은 해결책은s.replace('.','',1).isdigit()

나는 어떤 한 벤치 마크 다른 접근 방법을 비교하는

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

import re    
def is_number_regex(s):
    """ Returns True is string is a number. """
    if re.match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

문자열이 숫자가 아닌 경우 except-block은 상당히 느립니다. 그러나 더 중요한 것은 try-except 방법이 과학적 표기법을 올바르게 처리하는 유일한 방법입니다.

funcs = [
          is_number_tryexcept, 
          is_number_regex,
          is_number_repl_isdigit
          ]

a_float = '.1234'

print('Float notation ".1234" is not supported by:')
for f in funcs:
    if not f(a_float):
        print('\t -', f.__name__)

플로트 표기법 ".1234"는 다음에서 지원되지 않습니다.
-is_number_regex

scientific1 = '1.000000e+50'
scientific2 = '1e50'


print('Scientific notation "1.000000e+50" is not supported by:')
for f in funcs:
    if not f(scientific1):
        print('\t -', f.__name__)




print('Scientific notation "1e50" is not supported by:')
for f in funcs:
    if not f(scientific2):
        print('\t -', f.__name__)

과학 표기법 "1.000000e + 50"은 다음에서 지원하지 않습니다.
-is_number_regex
-is_number_repl_isdigit
과학 표기법 "1e50"은 다음에서 지원하지 않습니다.
-is_number_regex
-is_number_repl_isdigit

편집 : 벤치 마크 결과

import timeit

test_cases = ['1.12345', '1.12.345', 'abc12345', '12345']
times_n = {f.__name__:[] for f in funcs}

for t in test_cases:
    for f in funcs:
        f = f.__name__
        times_n[f].append(min(timeit.Timer('%s(t)' %f, 
                      'from __main__ import %s, t' %f)
                              .repeat(repeat=3, number=1000000)))

다음 기능들이 테스트 된 곳

from re import match as re_match
from re import compile as re_compile

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

def is_number_regex(s):
    """ Returns True is string is a number. """
    if re_match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


comp = re_compile("^\d+?\.\d+?$")    

def compiled_regex(s):
    """ Returns True is string is a number. """
    if comp.match(s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

여기에 이미지 설명을 입력하십시오


15
멋진 차트 +1. 나는 벤치 마크를보고 그래프를 보았습니다. 모든 TL; DR은 명확하고 직관적이었습니다.
jcchuks

@JCChuks에 동의합니다. 그래프는 모든 TL; DR을 빠르게 얻는 데 도움이됩니다. 그러나 나는이 답변 의 시작 부분에 TL; DR (예 : TL; DR : 최고의 해결책 s.replace('.','',1).isdigit())이 나타나야 한다고 생각합니다 . 어쨌든 그것은 받아 들여야합니다. 감사!
Simon C.

10
이 방법은 음수 (대시)를 처리하지 않습니다. 실수가 덜 일어나고 매번 작동 할 수 있기 때문에 float 메서드를 사용하는 것이 좋습니다.
Urchin

3
주목해야 할 것은 대시가있을 수 없다고 가정하더라도 대소 숫자 교체 방법은 숫자가 아닌 경우에만 (빠른 결과) 빠르며 try-except 방법은 숫자에 대해 더 빠릅니다 (참 결과)입니다. 대부분의 입력이 유효한 입력이면 시험 제외 솔루션을 사용하는 것이 좋습니다.
Markus von Broady

1
'1.5e-9'음수 와 같은 지수 표기법에서는 작동하지 않습니다 .
EL_DON

68

고려해야 할 한 가지 예외가 있습니다 : 문자열 'NaN'

is_number가 'NaN'에 대해 FALSE를 반환하도록하려면 Python이 숫자가 아닌 숫자의 표현으로 변환 할 때이 코드가 작동하지 않습니다 (ID 문제에 대한 대화).

>>> float('NaN')
nan

그렇지 않으면 실제로 광범위하게 사용하는 코드에 대해 실제로 감사드립니다. :)

지.


2
실제로, 전달 된 텍스트가 실제로 숫자의 표현이 아닌 경우 NaN(가 아닌 False) 반환하는 것이 좋습니다 . 그것을 확인하는 것은 일종의 고통입니다 (Python의 float유형에는 실제로 방법이 필요합니다). 오류를 생성하지 않고 계산에 사용할 수 있으며 결과 만 확인하면됩니다.
kindall

7
또 다른 예외는 문자열 'inf'입니다. 어느 infNaN또한 접두어 할 수 있습니다 +또는 -여전히 및 접수.
agf

4
NaN 및 Inf에 대해 False를 반환하려면 line을 x = float (s)로 변경하십시오. (x == x) 및 (x-1! = x)를 반환합니다. 이것은 Inf와 NaN을 제외한 모든 수레에 대해 True를 반환해야합니다
RyanN

5
x-1 == x보다 큰 수레에 대해서는 사실입니다 inf. Python 3.2부터 math.isfiniteNaN 또는 무한이 아닌 숫자를 테스트하거나 그 이전 math.isnan과 둘 다를 확인할 math.isinf수 있습니다.
Steve Jessop

56

이건 어때요:

'3.14'.replace('.','',1).isdigit()

'.'가 없거나없는 경우에만 true를 반환합니다. 자릿수로.

'3.14.5'.replace('.','',1).isdigit()

거짓을 반환합니다

편집 : 방금 다른 의견을 보았습니다 ... .replace(badstuff,'',maxnum_badstuff)다른 경우에 대해 추가 할 수 있습니다. 임의의 조미료가 아닌 소금을 통과하면 ( xkcd # 974 ) 이것이 잘됩니다. : P


7
그러나 이것은 음수를 설명하지 않습니다.
Michael Barton

5
또는 지수가있는 숫자 1.234e56(또한 +1.234E+56여러 변형 으로 쓰여질 수도 있음 ).
Alfe

re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')숫자를 결정하는 더 나은 일을해야합니다 (그러나 전부는 아닙니다, 나는 그것을 주장하지는 않습니다). 질문자의 원래 코드를 사용하는 것이 훨씬 좋습니다.
볼드 릭크

이 솔루션 마음에 들지 않으면 다운 보팅하기 전에이 내용을 읽으 십시오!
aloisdg가 codidact.com으로 이동

이게 내가이 웹 사이트에서 본 가장 똑똑한 해결책이야!
Karam Qusai

41

추악하고 느릴뿐만 아니라 어색한 것 같습니다.

익숙해지는 데 다소 시간이 걸릴 수 있지만 이것은 파이썬을 사용하는 방법입니다. 이미 지적했듯이 대안은 더 나쁩니다. 그러나 이런 식으로 일을하는 것의 또 다른 장점은 다형성입니다.

오리 타이핑의 기본 개념은 "걸 으면서 오리처럼 말하면 오리입니다." 플로트로 변환 할 수 있는지 확인하는 방법을 변경할 수 있도록 문자열을 서브 클래스 화해야한다면 어떻게해야합니까? 아니면 다른 물체를 완전히 테스트하기로 결정한 경우 어떻게해야합니까? 위의 코드를 변경하지 않고도 이러한 작업을 수행 할 수 있습니다.

다른 언어는 인터페이스를 사용하여 이러한 문제를 해결합니다. 다른 스레드에 어떤 솔루션이 더 나은지 분석을 저장하겠습니다. 그러나 요점은 파이썬이 결정의 오리 타이핑 측면에 결정적이라는 것입니다. 파이썬에서 많은 프로그래밍을 할 계획이라면 아마도 이와 같은 구문에 익숙해 져야 할 것입니다 (그러나 이것이 의미는 아닙니다 물론 좋아해야합니다).

고려해야 할 또 다른 사항 : 파이썬은 다른 많은 언어 (예 : .Net보다 30 배 빠름)에 비해 예외를 던지고 잡는 데 매우 빠릅니다. 심지어 언어 자체는 예외가 아닌 예외적 인 정상적인 프로그램 조건을 전달하기 위해 예외를 발생시킵니다 (for 루프를 사용할 때마다). 따라서 중요한 문제가 발견 될 때 까지이 코드의 성능 측면에 대해 너무 걱정하지 않아도됩니다.


1
파이썬이 기본 함수에 예외를 사용하는 또 다른 일반적인 장소는에 싸여 hasattr()있는 getattr()호출 try/except입니다. 하지만 예외 처리는 너무 사실이 될 것입니다 뭔가를 사용하여, 정상적인 흐름 제어보다 느린 대부분의 시간을 성능이 저하 될 수 있습니다.
kindall

원 라이너를 원한다면 SOL
Basic

또한 pythonic은 값싼 예외를 갖는 것의 영향과 관련하여 "허가보다 용서를 구하는 것이 더 낫다"는 아이디어입니다.
heltonbiker

40

Alfe가 지적한 후에 업데이트되었으므로 복잡한 핸들로 플로트를 별도로 확인할 필요가 없습니다.

def is_number(s):
    try:
        complex(s) # for int, long, float and complex
    except ValueError:
        return False

    return True

이전에 말했다 : 드문 경우이지만 float로 표현 할 수없는 복잡한 숫자 (예 : 1 + 2i)를 확인해야 할 수도 있습니다.

def is_number(s):
    try:
        float(s) # for int, long and float
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False

    return True

14
동의하지 않습니다. 일반적으로 사용하는 경우는 매우 드물며, 0.0001 %의 오작동 가능성을 위해 추가 작업으로 호출에 부담을주는 것보다 is_complex_number () 호출을 사용하는 것이 좋습니다.
Jiminion

3
float()물건을 완전히 벗기고 complex()전화가 성공했는지 확인하십시오 . 에 의해 파싱 된 모든 것이에 의해 파싱 될 float()수 있습니다 complex().
Alfe

이 함수는 Pandas의 NaN 및 Inf 값을 숫자 값으로 반환합니다.
fixxxer

complex('(01989)')을 반환 (1989+0j)합니다. 그러나 float('(01989)')실패합니다. 그래서 나는 사용하는 complex것이 좋지 않다고 생각합니다.
plhn

26

위해 int이것을 사용 :

>>> "1221323".isdigit()
True

그러나 float우리에게는 약간의 트릭이 필요합니다. ;-). 모든 플로트 숫자에는 하나의 점이 있습니다 ...

>>> "12.34".isdigit()
False
>>> "12.34".replace('.','',1).isdigit()
True
>>> "12.3.4".replace('.','',1).isdigit()
False

또한 음수의 경우 다음을 추가하십시오 lstrip().

>>> '-12'.lstrip('-')
'12'

이제 우리는 보편적 인 방법을 얻습니다.

>>> '-12.34'.lstrip('-').replace('.','',1).isdigit()
True
>>> '.-234'.lstrip('-').replace('.','',1).isdigit()
False

2
1.234e56유사하거나 유사한 것을 처리하지 않습니다 . 또한, 그것이 당신 99999999999999999999e99999999999999999999이 숫자가 아닌 것을 어떻게 알 수 있는지에 관심이 있습니다 . 파싱하려고하면 빨리 알아냅니다.
Alfe

50m 문자열 목록에서 허용되는 솔루션보다 ~ 30 % 빠르며 5k 문자열 목록에서 150 % 빠릅니다. 👏
Zev Averbach

15

그냥 모방 C #

C #에는 스칼라 값의 구문 분석을 처리하는 두 가지 함수가 있습니다.

  • Float.Parse ()
  • Float.TryParse ()

float.parse () :

def parse(string):
    try:
        return float(string)
    except Exception:
        throw TypeError

참고 : 예외를 TypeError로 변경 한 이유가 궁금하다면 문서를 참조하십시오 .

float.try_parse () :

def try_parse(string, fail=None):
    try:
        return float(string)
    except Exception:
        return fail;

참고 : 부울 'False'는 여전히 값 유형이므로 반환하지 않습니다. 실패를 나타내는 것이 더 좋습니다. 물론 다른 것을 원한다면 fail 매개 변수를 원하는대로 변경할 수 있습니다.

'parse ()'및 'try_parse ()'를 포함하도록 float를 확장하려면 이러한 메서드를 추가하려면 'float'클래스를 monkeypatch해야합니다.

기존 기능을 존중하려면 코드는 다음과 같아야합니다.

def monkey_patch():
    if(!hasattr(float, 'parse')):
        float.parse = parse
    if(!hasattr(float, 'try_parse')):
        float.try_parse = try_parse

SideNote : 개인적으로 YMMV 이외의 언어를 사용하는 것처럼 느끼기 때문에 Monkey Punching이라고합니다.

용법:

float.parse('giggity') // throws TypeException
float.parse('54.3') // returns the scalar value 54.3
float.tryParse('twank') // returns None
float.tryParse('32.2') // returns the scalar value 32.2

그리고 위대한 현자 Pythonas는 Holy See Sharpisus에게 "당신이 할 수있는 모든 것이 더 잘할 수 있습니다.


나는 최근에 주로 JS로 코딩하고 실제로 이것을 테스트하지 않았으므로 약간의 오류가있을 수 있습니다. 어떤 것이 있으면 내 실수를 바로 잡으십시오.
Evan Plaice 2012

복소수에 대한 지원을 추가하려면 @Matthew Wilcoxson의 답변을 참조하십시오. stackoverflow.com/a/3335060/290340 .
Evan Plaice 2019

1
!대신에 사용하는 것이 not사소한 오류 일 수 있지만 floatCPython 의 기본 제공 속성에 속성을 할당 할 수는 없습니다 .
BlackJack

15

숫자가 아닌 문자열의 경우 try: except: 경우 실제로 정규식보다 느립니다. 유효한 숫자 문자열의 경우 정규식이 느립니다. 따라서 적절한 방법은 입력에 따라 다릅니다.

당신이 성능 바인드에 있다는 것을 발견하면, 당신은 새로운 서드 파티 모듈을 호출 사용할 수 있습니다 fastnumbers 라는 기능을 제공 isfloat을 . 전체 공개, 나는 저자입니다. 나는 그 결과를 아래의 타이밍에 포함시켰다.


from __future__ import print_function
import timeit

prep_base = '''\
x = 'invalid'
y = '5402'
z = '4.754e3'
'''

prep_try_method = '''\
def is_number_try(val):
    try:
        float(val)
        return True
    except ValueError:
        return False

'''

prep_re_method = '''\
import re
float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match
def is_number_re(val):
    return bool(float_match(val))

'''

fn_method = '''\
from fastnumbers import isfloat

'''

print('Try with non-number strings', timeit.timeit('is_number_try(x)',
    prep_base + prep_try_method), 'seconds')
print('Try with integer strings', timeit.timeit('is_number_try(y)',
    prep_base + prep_try_method), 'seconds')
print('Try with float strings', timeit.timeit('is_number_try(z)',
    prep_base + prep_try_method), 'seconds')
print()
print('Regex with non-number strings', timeit.timeit('is_number_re(x)',
    prep_base + prep_re_method), 'seconds')
print('Regex with integer strings', timeit.timeit('is_number_re(y)',
    prep_base + prep_re_method), 'seconds')
print('Regex with float strings', timeit.timeit('is_number_re(z)',
    prep_base + prep_re_method), 'seconds')
print()
print('fastnumbers with non-number strings', timeit.timeit('isfloat(x)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with integer strings', timeit.timeit('isfloat(y)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with float strings', timeit.timeit('isfloat(z)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print()

Try with non-number strings 2.39108395576 seconds
Try with integer strings 0.375686168671 seconds
Try with float strings 0.369210958481 seconds

Regex with non-number strings 0.748660802841 seconds
Regex with integer strings 1.02021503448 seconds
Regex with float strings 1.08564686775 seconds

fastnumbers with non-number strings 0.174362897873 seconds
fastnumbers with integer strings 0.179651021957 seconds
fastnumbers with float strings 0.20222902298 seconds

보시다시피

  • try: except: 숫자 입력의 경우 빠르지 만 유효하지 않은 입력의 경우 매우 느립니다.
  • 정규식은 입력이 유효하지 않을 때 매우 효율적입니다
  • fastnumbers 두 경우 모두에서 승리

나는 정정했다 :-} 그것은 단지 이것을하고있는 것처럼 보이지 않았다. 아마 이름이 좋아 사용 prep_code_basis하고 prep_code_re_method내 실수를 방지했을 것입니다.
Alfe

적어도 isfloat기능에 대해 모듈의 작동 방식을 설명하고 있습니까?
Solomon Ucko

@SolomonUcko 다음은 문자열 검사 부분의 소스 코드에 대한 링크입니다 : github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/... . 기본적으로 문자열의 각 문자를 순서대로 살펴보고 유효한 부동 소수점 패턴을 따르는 지 확인합니다. 입력이 이미 숫자이면 빠른 PyFloat_Check 만 사용합니다 .
SethMMorton

1
이 스레드에서 가장 좋은 대안에 대해 테스트 한 결과이 솔루션이 훨씬 빠릅니다. 두 번째로 빠른 방법 str(s).strip('-').replace('.','',1).isdigit()은 약 10 배 느립니다!
Alexander McFarlane

14

나는 이것이 오래되었다는 것을 알고 있지만, 나는 이것을 찾는 사람에게 매우 가치가있을 수있는 가장 높은 투표 응답에서 누락 된 정보를 포함한다고 생각하는 답변을 추가 할 것입니다.

다음 각 방법에 대해 입력을 수락해야하는 경우 개수와 연결하십시오. (0-255가 아닌 정수의 음성 정의를 사용한다고 가정합니다.)

x.isdigit() x가 정수인지 확인하는 데 효과적입니다.

x.replace('-','').isdigit() x가 음수인지 확인하는 데 효과적입니다. (체크-첫 번째 위치)

x.replace('.','').isdigit() x가 10 진수인지 확인하는 데 효과적입니다.

x.replace(':','').isdigit() x가 비율인지 확인하는 데 효과적입니다.

x.replace('/','',1).isdigit() x가 분수인지 확인하는 데 효과적입니다.


1
분수의 x.replace('/','',1).isdigit()경우 2017 년 4 월 7 일과 같은 날짜를 숫자로 잘못 해석해야합니다.
Yuxuan Chen

조건을 연결하는 가장 좋은 방법 : stackoverflow.com/q/3411771/5922329
Daniel Braun

13

이 대답은 문자열을 찾는 예제와 함께 기능을 갖는 단계별 가이드를 제공합니다.

  • 양의 정수
  • 양수 / 음수-정수 / 부동
  • 숫자를 확인하는 동안 "NaN"(숫자가 아님) 문자열을 버리는 방법은 무엇입니까?

문자열이 양의 정수 인지 확인

str.isdigit()주어진 문자열이 양의 정수 인지 확인 하는 데 사용할 수 있습니다 .

샘플 결과 :

# For digit
>>> '1'.isdigit()
True
>>> '1'.isalpha()
False

문자열을 양수 / 음수로 검사-정수 / 부동

str.isdigit()False문자열이 음수 또는 부동 수이면를 반환 합니다 . 예를 들면 다음과 같습니다.

# returns `False` for float
>>> '123.3'.isdigit()
False
# returns `False` for negative number
>>> '-123'.isdigit()
False

당신이 원하는 경우 도 확인 부정의 와 정수float , 당신은 그것을 확인하기 위해 사용자 정의 함수를 작성할 수 있습니다 :

def is_number(n):
    try:
        float(n)   # Type-casting the string to `float`.
                   # If string is not a valid `float`, 
                   # it'll raise `ValueError` exception
    except ValueError:
        return False
    return True

샘플 실행 :

>>> is_number('123')    # positive integer number
True

>>> is_number('123.4')  # positive float number
True

>>> is_number('-123')   # negative integer number
True

>>> is_number('-123.4') # negative `float` number
True

>>> is_number('abc')    # `False` for "some random" string
False

숫자를 확인하는 동안 "NaN"(숫자가 아님) 문자열을 버리십시오

위 함수는 True파이썬이 숫자가 아닌 유효한 float이므로 "NAN"(숫자가 아님) 문자열 을 반환 합니다. 예를 들면 다음과 같습니다.

>>> is_number('NaN')
True

숫자가 "NaN"인지 확인하기 위해 math.isnan()다음과 같이 사용할 수 있습니다 .

>>> import math
>>> nan_num = float('nan')

>>> math.isnan(nan_num)
True

또는 추가 라이브러리를 가져 와서 확인하지 않으려면을 사용하여 라이브러리와 비교하여 간단히 확인할 수 있습니다 ==. float이 자신과 비교 False되면 Python이 반환 됩니다 nan. 예를 들면 다음과 같습니다.

# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False

따라서, 상기 함수는 is_number반환하도록 업데이트 될 수 False위해"NaN" 로서 :

def is_number(n):
    is_number = True
    try:
        num = float(n)
        # check for "nan" floats
        is_number = num == num   # or use `math.isnan(num)`
    except ValueError:
        is_number = False
    return is_number

샘플 실행 :

>>> is_number('Nan')   # not a number "Nan" string
False

>>> is_number('nan')   # not a number string "nan" with all lower cased
False

>>> is_number('123')   # positive integer
True

>>> is_number('-123')  # negative integer
True

>>> is_number('-1.12') # negative `float`
True

>>> is_number('abc')   # "some random" string
False

PS : 숫자 유형에 따라 각 검사에 대한 각 작업에는 추가 오버 헤드가 있습니다. is_number요구 사항에 맞는 기능 버전을 선택하십시오 .


12

float ()이 특별히 그 용도로 사용되므로 float로 캐스팅하고 ValueError를 잡는 것이 가장 빠른 방법 일 것입니다. 문자열 구문 분석 (정규식 등)이 필요한 다른 것은이 작업에 맞게 조정되지 않았기 때문에 느려질 수 있습니다. 내 $ 0.02.


11
"2e-2"달러도 부동입니다 (float 사용에 대한 추가 인수)
tzot

8
@tzot 절대로 화폐 가치를 표현하기 위해 float를 사용하지 마십시오.
Luke

6
@Luke : 화폐 가치를 표현하기 위해 float를 사용하는 것은 결코 제안하지 않았지만 나는 당신에게 전적으로 동의합니다. 방금 통화 가치 를 수레로 표현할 있다고 말했습니다. :
tzot

11

유니 코드 문자열을 사용할 수 있으며 원하는 것을 수행하는 방법이 있습니다.

>>> s = u"345"
>>> s.isnumeric()
True

또는:

>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True

http://www.tutorialspoint.com/python/string_isnumeric.htm

http://docs.python.org/2/howto/unicode.html


2
음이 아닌 정수의 경우 괜찮습니다 ;-)
andilabs

1
s.isdecimal()s문자열이 음이 아닌 정수 인지 확인합니다 . 거부 s.isnumeric()하는 문자를 포함 int()합니다.
jfs

9

어떤 방법이 가장 빠른지 알고 싶었습니다. 전체적으로 가장 우수하고 일관된 결과가 check_replace기능에 의해 제공되었습니다 . check_exception함수에서 가장 빠른 결과를 얻었 지만 예외가 발생하지 않은 경우에만 해당됩니다. 즉, 코드가 가장 효율적이지만 예외를 발생시키는 오버 헤드는 상당히 큽니다.

성공적인 캐스트를 확인하는 것이 정확한 유일한 방법입니다. 예를 들어,이 방법은 작동 check_exception하지만 다른 두 테스트 함수는 유효한 float에 대해 False를 반환합니다.

huge_number = float('1e+100')

벤치 마크 코드는 다음과 같습니다.

import time, re, random, string

ITERATIONS = 10000000

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self
    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

def check_regexp(x):
    return re.compile("^\d*\.?\d*$").match(x) is not None

def check_replace(x):
    return x.replace('.','',1).isdigit()

def check_exception(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

to_check = [check_regexp, check_replace, check_exception]

print('preparing data...')
good_numbers = [
    str(random.random() / random.random()) 
    for x in range(ITERATIONS)]

bad_numbers = ['.' + x for x in good_numbers]

strings = [
    ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randint(1,10)))
    for x in range(ITERATIONS)]

print('running test...')
for func in to_check:
    with Timer() as t:
        for x in good_numbers:
            res = func(x)
    print('%s with good floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in bad_numbers:
            res = func(x)
    print('%s with bad floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in strings:
            res = func(x)
    print('%s with strings: %s' % (func.__name__, t.interval))

2017 MacBook Pro 13의 Python 2.7.10 결과는 다음과 같습니다.

check_regexp with good floats: 12.688639
check_regexp with bad floats: 11.624862
check_regexp with strings: 11.349414
check_replace with good floats: 4.419841
check_replace with bad floats: 4.294909
check_replace with strings: 4.086358
check_exception with good floats: 3.276668
check_exception with bad floats: 13.843092
check_exception with strings: 15.786169

2017 MacBook Pro 13의 Python 3.6.5 결과는 다음과 같습니다.

check_regexp with good floats: 13.472906000000009
check_regexp with bad floats: 12.977665000000016
check_regexp with strings: 12.417542999999995
check_replace with good floats: 6.011045999999993
check_replace with bad floats: 4.849356
check_replace with strings: 4.282754000000011
check_exception with good floats: 6.039081999999979
check_exception with bad floats: 9.322753000000006
check_exception with strings: 9.952595000000002

2017 MacBook Pro 13에서 PyPy 2.7.13의 결과는 다음과 같습니다.

check_regexp with good floats: 2.693217
check_regexp with bad floats: 2.744819
check_regexp with strings: 2.532414
check_replace with good floats: 0.604367
check_replace with bad floats: 0.538169
check_replace with strings: 0.598664
check_exception with good floats: 1.944103
check_exception with bad floats: 2.449182
check_exception with strings: 2.200056

10
또한 유효하지 않은 경우에 대한 성능을 테스트해야합니다. 정확하게 "느린"부분 인이 숫자들에 대해서는 예외가 발생하지 않습니다.
Ugo Méda

1
@ UgoMéda 나는 2013 년부터 당신의 조언을 받아 그것을했다 :)
Ron Reiter

"성공적인 캐스트를 확인하는 것이 정확한 유일한 방법입니다"<-이것은 실제로 사실이 아닙니다. 위의 답변에서 정규 표현식을 사용하여 테스트를 실행했으며 실제로 정규 표현식보다 빠르게 실행됩니다. 위의 답변에 결과를 추가하겠습니다.
David Ljung Madison 스텔라

우연히도 재미있는 점으로, 당신의 나쁜 숫자 생성자는 실제로 약간의 법적인 숫자를 만들 수 있습니다. :)
David Ljung Madison Stellar

8

따라서 모든 것을 종합하여 Nan, 무한대 및 복소수를 확인하려면 (i가 아닌 j로 지정 된 것처럼 보입니다 (예 : 1 + 2j)) 결과는 다음과 같습니다.

def is_number(s):
    try:
        n=str(float(s))
        if n == "nan" or n=="inf" or n=="-inf" : return False
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False
    return True

지금까지 가장 좋은 답변입니다. 감사
anish

6

입력은 다음과 같습니다.

a="50" b=50 c=50.1 d="50.1"


1 일반 입력 :

이 기능의 입력은 모든 것이 될 수 있습니다!

주어진 변수가 숫자인지 확인합니다. 숫자 문자열은 선택적 부호, 자릿수, 선택적 10 진수 부분 및 선택적 지수 부분으로 구성됩니다. 따라서 + 0123.45e6은 유효한 숫자 값입니다. 16 진법 (예 : 0xf4c3b00c) 및 이진법 (예 : 0b10100111001) 표기법은 허용되지 않습니다.

is_numeric 함수

import ast
import numbers              
def is_numeric(obj):
    if isinstance(obj, numbers.Number):
        return True
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            #if used + or - in digit :
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

테스트:

>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True

is_float 함수

주어진 변수가 실수인지 확인합니다. 부동 문자열은 선택적 부호, 자릿수, ...로 구성됩니다.

import ast

def is_float(obj):
    if isinstance(obj, float):
        return True
    if isinstance(obj, int):
        return False
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        if not isinstance(nodes[-1].n, float):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

테스트:

>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True

뭐가 ast 입니까?


2- 가변 콘텐츠가 문자열 :

사용 str.isdigit () 메소드

>>> a=454
>>> a.isdigit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'isdigit'
>>> a="454"
>>> a.isdigit()
True

3- 숫자 입력 :

int 값을 감지하십시오.

>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>> 

플로트 감지 :

>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True

" ast" 는 무엇 입니까?

4

나는 약간의 속도 테스트를했다. 문자열 인 경우라고하자 가능성이 번호로 제외 / 시도 전략은 문자열이 가장 빠른 possible.If입니다 가능성이없는 숫자로 하고 관심있는 정수 점검, 그것은 몇 가지 테스트 (isdigit에 플러스 제목을 할 worths '-'). 플로트 번호를 확인하려면 try / except 코드 whitout 이스케이프 를 사용해야합니다 .


4

문자열이 기본 유형 (float, int, str, bool)으로 캐스팅되었는지 확인해야했습니다. 인터넷에서 아무것도 찾지 못하면 이것을 만들었습니다.

def str_to_type (s):
    """ Get possible cast type for a string

    Parameters
    ----------
    s : string

    Returns
    -------
    float,int,str,bool : type
        Depending on what it can be cast to

    """    
    try:                
        f = float(s)        
        if "." not in s:
            return int
        return float
    except ValueError:
        value = s.upper()
        if value == "TRUE" or value == "FALSE":
            return bool
        return type(s)

str_to_type("true") # bool
str_to_type("6.0") # float
str_to_type("6") # int
str_to_type("6abc") # str
str_to_type(u"6abc") # unicode       

유형을 캡처하여 사용할 수 있습니다

s = "6.0"
type_ = str_to_type(s) # float
f = type_(s) 

3

RyanN은 제안합니다

NaN 및 Inf에 대해 False를 반환하려면 line을 x = float (s)로 변경하십시오. (x == x) 및 (x-1! = x)를 반환합니다. Inf와 NaN을 제외한 모든 float에 대해 True를 반환해야합니다.

그러나 충분히 큰 플로트의 경우 x-1 == xtrue를 반환 하기 때문에 이것은 작동하지 않습니다 . 예를 들어2.0**54 - 1 == 2.0**54


3

난 당신의 솔루션을 잘 생각하지만 거기에 있다 올바른 정규 표현식 구현.

정당하지 않다고 생각되는 이러한 답변에 대한 많은 정규 표현식이 싫어 보입니다. 정규 표현식은 합리적으로 깨끗하고 정확하며 빠릅니다. 그것은 당신이하려는 일에 달려 있습니다. 원래 질문은 "문자열에 따라 문자열을 숫자 (부동)로 표시 할 수 있는지 확인"하는 방법이었습니다. 아마도 유효한지 확인한 후에 숫자 / 부동 값을 사용하려고 할 것입니다.이 경우 시도 / 제외가 의미가 있습니다. 그러나 어떤 이유로 든 문자열 을 확인하려는 경우숫자 인지 경우그런 다음 정규 표현식도 제대로 작동하지만 올바르게 이해하기는 어렵습니다. 예를 들어, 지금까지 대부분의 정규식 답변이 파이썬과 관련하여 부동 소수점 인 정수 부분 (예 : ".7")이없는 문자열을 올바르게 구문 분석하지 않는다고 생각합니다. 그리고 분수 부분이 필요하지 않은 단일 정규식에서 확인하는 것은 약간 까다 롭습니다. 이것을 보여주기 위해 두 개의 정규 표현식을 포함 시켰습니다.

"숫자"가 무엇인지에 대한 흥미로운 질문을 제기합니다. 파이썬에서 float로 유효한 "inf"를 포함합니까? 또는 "숫자"이지만 파이썬으로 표현할 수없는 숫자 (예 : 부동 최대 값보다 큰 숫자)를 포함합니까?

숫자를 구문 분석하는 방법에 대한 모호성도 있습니다. 예를 들어 "--20"은 어떻습니까? 이것이 "숫자"입니까? 이것이 "20"을 나타내는 합법적 인 방법입니까? 파이썬은 "var = --20"을하도록하고 20으로 설정합니다 (실제로 표현식으로 취급하기 때문이지만) float ( "-20")는 작동하지 않습니다.

어쨌든, 더 많은 정보없이 여기에 파이썬이 파싱 할 때 모든 정수와 수레 다루는 정규식이 있습니다 .

# Doesn't properly handle floats missing the integer part, such as ".7"
SIMPLE_FLOAT_REGEXP = re.compile(r'^[-+]?[0-9]+\.?[0-9]+([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           mantissa (34)
                            #                    exponent (E+56)

# Should handle all floats
FLOAT_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           OR
                            #             int/mantissa (12.34)
                            #                            exponent (E+56)

def is_float(str):
  return True if FLOAT_REGEXP.match(str) else False

몇 가지 예제 테스트 값 :

True  <- +42
True  <- +42.42
False <- +42.42.22
True  <- +42.42e22
True  <- +42.42E-22
False <- +42.42e-22.8
True  <- .42
False <- 42nope

@ ron-reiter의 답변 에서 벤치마킹 코드를 실행하면 이 정규식이 실제로 일반 정규식보다 빠르며 예외보다 잘못된 값을 처리하는 데 훨씬 빠릅니다. 결과 :

check_regexp with good floats: 18.001921
check_regexp with bad floats: 17.861423
check_regexp with strings: 17.558862
check_correct_regexp with good floats: 11.04428
check_correct_regexp with bad floats: 8.71211
check_correct_regexp with strings: 8.144161
check_replace with good floats: 6.020597
check_replace with bad floats: 5.343049
check_replace with strings: 5.091642
check_exception with good floats: 5.201605
check_exception with bad floats: 23.921864
check_exception with strings: 23.755481

맞습니다. 반대 사례에 대해 듣고 싶습니다. :)
David Ljung Madison Stellar

2
import re
def is_number(num):
    pattern = re.compile(r'^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$')
    result = pattern.match(num)
    if result:
        return True
    else:
        return False


​>>>: is_number('1')
True

>>>: is_number('111')
True

>>>: is_number('11.1')
True

>>>: is_number('-11.1')
True

>>>: is_number('inf')
False

>>>: is_number('-inf')
False

2
1e6숫자를 나타내는 것을 고려하지 않습니까?
Mark Dickinson

1

여기 내 간단한 방법이 있습니다. 일부 문자열을 반복하고 숫자로 판명되면 배열에 추가하고 싶다고 가정 해 봅시다.

try:
    myvar.append( float(string_to_check) )
except:
    continue

myvar.apppend를 숫자로 밝혀지면 문자열로 수행하려는 작업으로 바꾸십시오. 아이디어는 float () 연산을 사용하고 리턴 된 오류를 사용하여 문자열이 숫자인지 여부를 판별하는 것입니다.


배열에 문제가있는 경우 예외를 트리거하지 않도록 해당 함수의 추가 부분을 else 문으로 이동해야합니다.
DarwinSurvivor

1

또한 언급 한 함수를 사용했지만 곧 문자열을 "Nan", "Inf"로 표시하고 그 변형이 숫자로 간주됩니다. 따라서 함수의 개선 된 버전을 제안합니다. 그러면 해당 유형의 입력에서 false가 반환되고 "1e3"변형이 실패하지 않습니다.

def is_float(text):
    try:
        float(text)
        # check for nan/infinity etc.
        if text.isalpha():
            return False
        return True
    except ValueError:
        return False

1

이 코드는 정규식을 사용하지 않고 지수, 부동 소수점 및 정수를 처리합니다.

return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False

1

사용자 도우미 기능 :

def if_ok(fn, string):
  try:
    return fn(string)
  except Exception as e:
    return None

그때

if_ok(int, my_str) or if_ok(float, my_str) or if_ok(complex, my_str)
is_number = lambda s: any([if_ok(fn, s) for fn in (int, float, complex)])

0

True 및 False보다 유용한 값을 반환하여 예외 기술을 유용한 방식으로 일반화 할 수 있습니다. 예를 들어이 함수는 따옴표를 둥근 문자열로 표시하지만 숫자 만 남겨 둡니다. R에 대한 변수 정의를 만들기 위해 빠르고 더러운 필터에 필요한 것입니다.

import sys

def fix_quotes(s):
    try:
        float(s)
        return s
    except ValueError:
        return '"{0}"'.format(s)

for line in sys.stdin:
    input = line.split()
    print input[0], '<- c(', ','.join(fix_quotes(c) for c in input[1:]), ')'

0

나는이 스레드로 이끌어 낸 문제, 즉 가장 직관적 인 방법으로 데이터 모음을 문자열과 숫자로 변환하는 방법을 연구하고있었습니다. 원래 코드를 읽은 후 필요한 두 가지 방법이 다르다는 것을 깨달았습니다.

1-문자열이 정수를 나타내는 경우 정수 결과를 원했습니다.

2-숫자 또는 문자열 결과가 데이터 구조에 달라 붙기를 원했습니다.

그래서 나는이 파생물을 생성하기 위해 원래 코드를 수정했습니다.

def string_or_number(s):
    try:
        z = int(s)
        return z
    except ValueError:
        try:
            z = float(s)
            return z
        except ValueError:
            return s

0

이 시도.

 def is_number(var):
    try:
       if var == int(var):
            return True
    except Exception:
        return False

응답하지 is_number('10')
않음

@geotheory, "응답 실패"는 무엇을 의미합니까?
Solomon Ucko

0
def is_float(s):
    if s is None:
        return False

    if len(s) == 0:
        return False

    digits_count = 0
    dots_count = 0
    signs_count = 0

    for c in s:
        if '0' <= c <= '9':
            digits_count += 1
        elif c == '.':
            dots_count += 1
        elif c == '-' or c == '+':
            signs_count += 1
        else:
            return False

    if digits_count == 0:
        return False

    if dots_count > 1:
        return False

    if signs_count > 1:
        return False

    return True
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.