1976 Stimmen

Wie prüfe ich, ob eine Zeichenkette eine Zahl (Float) ist?

Wie kann man am besten prüfen, ob eine Zeichenkette in Python als Zahl dargestellt werden kann?

Die Funktion, die ich derzeit habe, ist:

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

Das ist nicht nur hässlich und langsam, sondern wirkt auch klobig. Ich habe jedoch keine bessere Methode gefunden, da der Aufruf von float() in der Hauptfunktion ist noch schlimmer.

101 Stimmen

Was ist falsch an Ihrer derzeitigen Lösung? Sie ist kurz, schnell und lesbar.

7 Stimmen

Und Sie müssen nicht nur True oder False zurückgeben. Sie können stattdessen den Wert entsprechend modifiziert zurückgeben - zum Beispiel könnten Sie dies verwenden, um Nicht-Zahlen in Anführungszeichen zu setzen.

10 Stimmen

Wäre es nicht besser, im Falle einer erfolgreichen Konvertierung das Ergebnis von float(s) zurückzugeben? Sie haben immer noch die Erfolgsprüfung (Ergebnis ist False) und Sie haben die Umwandlung, die Sie wahrscheinlich sowieso wollen.

49voto

Matthew Wilcoxson Punkte 3154

Aktualisiert, nachdem Alfe darauf hingewiesen hat, dass man nicht gesondert nach float suchen muss, da complex beides behandelt:

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

    return True

Zuvor gesagt: In einigen seltenen Fällen kann es erforderlich sein, auch komplexe Zahlen zu prüfen (z.B. 1+2i), die nicht durch eine Fließkommazahl dargestellt werden können:

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

15 Stimmen

Ich bin anderer Meinung. Das ist im normalen Gebrauch sehr unwahrscheinlich, und es wäre besser, einen is_complex_number()-Aufruf zu erstellen, wenn Sie sie verwenden, anstatt einen Aufruf mit zusätzlichen Operationen für eine 0,0001%ige Chance einer Fehlbedienung zu belasten.

3 Stimmen

Sie können die float() vollständig zu löschen und nur auf die complex() Aufruf zum Erfolg. Alles geparst von float() kann geparst werden von complex() .

0 Stimmen

Diese Funktion gibt die NaNs und Inf-Werte von Pandas als numerische Werte zurück.

45voto

Jason Baker Punkte 180981

Das ist nicht nur hässlich und langsam, sondern wirkt auch klobig.

Es mag etwas gewöhnungsbedürftig sein, aber das ist die pythonische Art, es zu tun. Wie bereits gesagt wurde, sind die Alternativen schlechter. Aber es gibt noch einen weiteren Vorteil dieser Vorgehensweise: die Polymorphie.

Die zentrale Idee hinter der Enten-Typisierung ist, dass "wenn es wie eine Ente läuft und spricht, dann ist es eine Ente". Was ist, wenn Sie beschließen, dass Sie string unterklassifizieren müssen, damit Sie die Art und Weise ändern können, wie Sie bestimmen, ob etwas in einen float umgewandelt werden kann? Oder was ist, wenn Sie beschließen, ein ganz anderes Objekt zu testen? Sie können diese Dinge tun, ohne den obigen Code ändern zu müssen.

Andere Sprachen lösen diese Probleme mit Hilfe von Schnittstellen. Ich werde die Analyse, welche Lösung besser ist, für einen anderen Thread aufheben. Der Punkt ist jedoch, dass Python entschieden auf der Duck-Typing-Seite der Gleichung ist, und Sie werden sich wahrscheinlich an eine solche Syntax gewöhnen müssen, wenn Sie vorhaben, viel in Python zu programmieren (aber das bedeutet natürlich nicht, dass Sie es mögen müssen).

Eine weitere Sache, die Sie vielleicht in Betracht ziehen möchten: Python ist im Vergleich zu vielen anderen Sprachen ziemlich schnell beim Werfen und Abfangen von Ausnahmen (30x schneller als .Net zum Beispiel). Die Sprache selbst löst sogar Ausnahmen aus, um nicht außergewöhnliche, normale Programmbedingungen zu kommunizieren (jedes Mal, wenn Sie eine for-Schleife verwenden). Daher würde ich mir nicht allzu viele Gedanken über die Leistungsaspekte dieses Codes machen, bis Sie ein größeres Problem bemerken.

1 Stimmen

Eine weitere häufige Stelle, an der Python Ausnahmen für grundlegende Funktionen verwendet, ist in hasattr() die nur eine getattr() Aufruf verpackt in einer try/except . Dennoch ist die Behandlung von Ausnahmen langsamer als die normale Flusskontrolle, so dass sie für etwas verwendet wird, das wahr sein wird die meiste Zeit kann zu Leistungseinbußen führen.

0 Stimmen

Wenn Sie einen Einzeiler wollen, sind Sie offenbar SOL

0 Stimmen

Ebenfalls pythonisch ist der Gedanke, dass es "besser ist, um Vergebung zu bitten als um Erlaubnis", was die Auswirkungen billiger Ausnahmen betrifft.

35voto

Moinuddin Quadri Punkte 43207

Diese Antwort bietet Schritt für Schritt Anleitung mit Funktion mit Beispielen zu finden, die Zeichenfolge ist:

  • Positive Ganzzahl
  • Positiv/negativ - Ganzzahl/Fließkomma
  • Wie zu verwerfen "NaN" (nicht eine Zahl) Zeichenfolgen bei der Überprüfung auf Zahl?

Prüfen Sie, ob die Zeichenkette positiv Ganzzahl

Sie können verwenden str.isdigit() um zu prüfen, ob die angegebene Zeichenkette positiv Ganzzahlig.

Ergebnisse der Stichprobe:

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

Prüfung auf String als positiv/negativ - Integer/Float

str.isdigit() gibt zurück. False wenn die Zeichenkette eine negativ Zahl oder eine Float-Zahl. Zum Beispiel:

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

Wenn Sie möchten, dass Prüfen Sie auch, ob die negativ ganze Zahlen und float dann können Sie eine benutzerdefinierte Funktion schreiben, um dies zu überprüfen:

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

Musterlauf:

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

Verwerfen von "NaN"-Strings (keine Zahl) bei der Prüfung auf Zahl

Die oben genannten Funktionen liefern True für die Zeichenkette "NAN" (Not a number), da sie für Python als Float gilt und keine Zahl darstellt. Zum Beispiel:

>>> is_number('NaN')
True

Um zu prüfen, ob die Zahl "NaN" ist, können Sie Folgendes verwenden math.isnan() als:

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

>>> math.isnan(nan_num)
True

Wenn Sie keine zusätzliche Bibliothek importieren möchten, um dies zu überprüfen, können Sie es auch einfach durch einen Vergleich mit sich selbst überprüfen, indem Sie == . Python gibt zurück False wenn nan float wird mit sich selbst verglichen. Zum Beispiel:

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

Daher wird oben Funktion is_number kann aktualisiert werden und liefert False para "NaN" als:

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

Musterlauf:

>>> 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: Jeder Vorgang für jede Prüfung, je nach Art der Nummer, ist mit zusätzlichem Overhead verbunden. Wählen Sie die Version von is_number Funktion, die Ihren Anforderungen entspricht._

34voto

Sdwdaw Punkte 1019

Für int dies verwenden:

>>> "1221323".isdigit()
True

Aber für float wir brauchen ein paar Tricks ;-). Jede Fließkommazahl hat einen Punkt...

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

Auch für negative Zahlen addieren Sie einfach lstrip() :

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

Und jetzt bekommen wir einen universellen Weg:

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

3 Stimmen

Er kann nicht mit Dingen umgehen wie 1.234e56 und ähnliches. Außerdem würde mich interessieren, wie Sie herausgefunden haben, dass 99999999999999999999e99999999999999999999 ist keine Zahl. Wer versucht, sie zu analysieren, findet das schnell heraus.

0 Stimmen

Dies läuft ~30% schneller als die akzeptierte Lösung auf einer Liste von 50m Strings, und 150% schneller auf einer Liste von 5k Strings.

1 Stimmen

Beachten Sie, dass >>> '--1234'.lstrip('-').replace('.','',1).isdigit() gibt true zurück; vielleicht nicht das, was erwartet wird

18voto

SethMMorton Punkte 40575

Für Zeichenketten aus Nicht-Zahlen, try: except: langsamer ist als reguläre Ausdrücke. Bei Zeichenketten mit gültigen Zahlen ist regex langsamer. Die geeignete Methode hängt also von Ihrer Eingabe ab.

Wenn Sie feststellen, dass Sie sich in einem Leistungsengpass befinden, können Sie ein neues Modul eines Drittanbieters namens fastnumbers die eine Funktion namens isfloat . Vollständige Offenlegung: Ich bin der Autor. Ich habe die Ergebnisse in die nachstehenden Zeitangaben aufgenommen.


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

Wie Sie sehen können

  • try: except: war schnell für numerische Eingaben, aber sehr langsam für eine ungültige Eingabe
  • regex ist sehr effizient, wenn die Eingabe ungültig ist
  • fastnumbers gewinnt in beiden Fällen

0 Stimmen

Ich korrigiere mich :-} Es sah nur nicht so aus, als würde es das tun. Vielleicht sollte man Namen wie prep_code_basis y prep_code_re_method hätte meinen Fehler verhindert.

0 Stimmen

Würden Sie bitte erklären, wie Ihr Modul funktioniert, zumindest für die isfloat Funktion?

0 Stimmen

@SolomonUcko Hier ist ein Link zum Quellcode für den Teil der Zeichenfolgenprüfung: github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/ . Grundsätzlich wird jedes Zeichen in der Zeichenkette der Reihe nach durchlaufen und überprüft, ob es einem Muster für eine gültige Gleitkommazahl folgt. Wenn die Eingabe bereits eine Zahl ist, verwendet es einfach die schnelle PyFloat_Prüfung .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X