Wie kann am besten überprüft werden, ob eine Zeichenfolge 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
Was nicht nur hässlich und langsam ist, sondern auch klobig erscheint. Ich habe jedoch keine bessere Methode gefunden, da das Aufrufen float
der Hauptfunktion noch schlimmer ist.
python
casting
floating-point
type-conversion
Daniel Goldberg
quelle
quelle
x = float('0.00'); if x: use_float(x);
Sie jetzt einen Fehler in Ihrem Code. Wahrheitswerte sind der Grund, warum diese Funktionen eine Ausnahme auslösen, anstatt überhaupt zurückzukehrenNone
. Eine bessere Lösung besteht darin, die Dienstprogrammfunktion zu vermeiden und den Aufruf zu umgeben, um in einem zu schweben,try catch
wenn Sie ihn verwenden möchten.Antworten:
Ich würde beides bestreiten.
Ein Regex oder eine andere String-Parsing-Methode wäre hässlicher und langsamer.
Ich bin mir nicht sicher, ob etwas viel schneller sein könnte als oben. Es ruft die Funktion auf und kehrt zurück. Try / Catch verursacht nicht viel Overhead, da die häufigste Ausnahme ohne umfangreiche Suche nach Stapelrahmen abgefangen wird.
Das Problem ist, dass jede numerische Konvertierungsfunktion zwei Arten von Ergebnissen hat
C (als Beispiel) hackt dies auf verschiedene Arten. Python legt es klar und explizit dar.
Ich denke, Ihr Code dafür ist perfekt.
quelle
try
Klausel aufzunehmen, also würde ich denreturn True
in eineelse
Klausel der setzentry
. Einer der Gründe ist, dass ich mit dem Code in der Frage, wenn ich ihn überprüfen müsste, überprüfen müsste, ob die zweite Anweisung in dertry
Klausel keinen ValueError auslösen kann: Zugegeben, dies erfordert nicht zu viel Zeit oder Gehirnleistung. aber warum welche verwenden, wenn keine benötigt wird?IsNumeric()
ich entweder einen Versuch / Fang oder einen anderen, der einen Versuch / Fang einwickelt. Ughif is_number(s): x = float(x) else: // fail
es die gleiche Anzahl von Codezeilen wie das enthälttry: x = float(x) catch TypeError: # fail
. Diese Utility-Funktion ist eine völlig unnötige Abstraktion.Wenn Sie nach Ganzzahlen (positive, vorzeichenlose) Ganzzahlen anstelle von Gleitkommazahlen suchen, können Sie die
isdigit()
Funktion für Zeichenfolgenobjekte verwenden.String-Methoden -
isdigit()
: Python2 , Python3Es gibt auch etwas in Unicode-Zeichenfolgen, mit dem ich mit Unicode nicht allzu vertraut bin - Ist dezimal / dezimal
quelle
isdigit()
undint()
haben unterschiedliche Meinungen darüber, was eine ganze Zahl ist, z. B. für das Unicode-Zeichenu'\u00b9'
:u'¹'.isdigit()
istTrue
aberint(u'¹')
erhöht ValueError.TL; DR Die beste Lösung ist
s.replace('.','',1).isdigit()
Ich habe einige Benchmarks durchgeführt , um die verschiedenen Ansätze zu vergleichen
Wenn die Zeichenfolge keine Zahl ist, ist der Ausnahmeblock ziemlich langsam. Noch wichtiger ist jedoch, dass die Try-Except-Methode der einzige Ansatz ist, der wissenschaftliche Notationen korrekt behandelt.
Die Float-Notation ".1234" wird nicht unterstützt von:
- is_number_regex
Die wissenschaftliche Notation "1.000000e + 50" wird nicht unterstützt von:
- is_number_regex
- is_number_repl_isdigit Die
wissenschaftliche Notation "1e50" wird nicht unterstützt von:
- is_number_regex
- is_number_repl_isdigit
EDIT: Die Benchmark-Ergebnisse
wo die folgenden Funktionen getestet wurden
quelle
s.replace('.','',1).isdigit()
) sollte am Anfang dieser Antwort erscheinen. In jedem Fall sollte es das akzeptierte sein. Vielen Dank!'1.5e-9'
oder mit Negativen.Es gibt eine Ausnahme, die Sie möglicherweise berücksichtigen möchten: die Zeichenfolge 'NaN'
Wenn Sie möchten, dass is_number FALSE für 'NaN' zurückgibt, funktioniert dieser Code nicht, da Python ihn in die Darstellung einer Zahl konvertiert, die keine Zahl ist (sprechen Sie über Identitätsprobleme):
Ansonsten sollte ich mich bei Ihnen für den Code bedanken, den ich jetzt ausgiebig benutze. :) :)
G.
quelle
NaN
könnte es ein guter Wert sein, (anstattFalse
) zurückzugeben, wenn der übergebene Text tatsächlich keine Darstellung einer Zahl ist. Das Überprüfen darauf ist eine Art Schmerz (Pythonsfloat
Typ benötigt wirklich eine Methode dafür), aber Sie können es in Berechnungen verwenden, ohne einen Fehler zu erzeugen, und müssen nur das Ergebnis überprüfen.'inf'
. Entwederinf
oderNaN
kann auch mit einem+
oder vorangestellt werden-
und wird trotzdem akzeptiert.x-1 == x
gilt für große schwimmer kleiner alsinf
. In Python 3.2 können Siemath.isfinite
nach Zahlen suchen, die weder NaN noch unendlich sind, oder beidemath.isnan
undmath.isinf
davor überprüfen .Wie wäre es damit:
was nur dann true zurückgibt, wenn es ein oder kein '.' gibt. in der Ziffernfolge.
wird false zurückgeben
edit: habe gerade einen weiteren Kommentar gesehen ... das Hinzufügen eines
.replace(badstuff,'',maxnum_badstuff)
für andere Fälle kann durchgeführt werden. Wenn Sie Salz und keine willkürlichen Gewürze geben (Ref: xkcd # 974 ), reicht dies aus: P.quelle
1.234e56
(die auch als+1.234E+56
und mehrere weitere Varianten geschrieben werden könnten ).re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')
sollte eine Zahl besser bestimmen (aber nicht alle, das behaupte ich nicht). Ich empfehle nicht, dies zu verwenden, weitaus besser, den Originalcode des Fragestellers zu verwenden.Es mag etwas gewöhnungsbedürftig sein, aber dies ist die pythonische Art, es zu tun. Wie bereits erwähnt, sind die Alternativen schlechter. Aber es gibt noch einen weiteren Vorteil, wenn man die Dinge so macht: Polymorphismus.
Die zentrale Idee hinter dem Tippen von Enten ist: "Wenn es wie eine Ente geht und spricht, dann ist es eine Ente." Was ist, wenn Sie entscheiden, dass Sie eine Zeichenfolge unterordnen müssen, damit Sie ändern können, wie Sie bestimmen, ob etwas in einen Float konvertiert werden kann? Oder was ist, wenn Sie sich entscheiden, ein anderes Objekt vollständig zu testen? Sie können diese Dinge tun, ohne den obigen Code ändern zu müssen.
Andere Sprachen lösen diese Probleme mithilfe von Schnittstellen. Ich werde die Analyse speichern, welche Lösung für einen anderen Thread besser ist. Der Punkt ist jedoch, dass Python entschieden auf der Seite der Ententypisierung der Gleichung steht und Sie sich wahrscheinlich an eine solche Syntax gewöhnen müssen, wenn Sie viel in Python programmieren möchten (aber das bedeutet nicht, dass dies der Fall ist du musst es natürlich mögen).
Eine andere Sache, die Sie vielleicht berücksichtigen sollten: Python ist im Vergleich zu vielen anderen Sprachen (30x schneller als beispielsweise .Net) ziemlich schnell beim Auslösen und Abfangen von Ausnahmen. Heck, 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 mich nicht zu sehr um die Leistungsaspekte dieses Codes kümmern, bis Sie ein signifikantes Problem bemerken.
quelle
hasattr()
eingetattr()
Aufruf, der in a eingeschlossen isttry/except
. Die Ausnahmebehandlung ist jedoch langsamer als die normale Flusskontrolle. Wenn Sie sie daher für etwas verwenden, das die meiste Zeit zutrifft, kann dies zu Leistungseinbußen führen.Aktualisiert, nachdem Alfe darauf hingewiesen hat, dass Sie nicht separat nach Float suchen müssen, da beide komplexe Handles:
Zuvor gesagt: In einigen seltenen Fällen müssen Sie möglicherweise auch nach komplexen Zahlen suchen (z. B. 1 + 2i), die nicht durch einen Float dargestellt werden können:
quelle
float()
Zeug komplett entfernen und einfach prüfen, ob dercomplex()
Anruf erfolgreich ist. Alles, was analysiert wird,float()
kann analysiert werdencomplex()
.complex('(01989)')
wird zurückkehren(1989+0j)
. Aberfloat('(01989)')
wird fehlschlagen. Daher denke ich, dass die Verwendungcomplex
keine gute Idee ist.Zur
int
Verwendung:Aber dafür
float
brauchen wir ein paar Tricks ;-). Jede Float-Nummer hat einen Punkt ...Auch für negative Zahlen einfach hinzufügen
lstrip()
:Und jetzt bekommen wir einen universellen Weg:
quelle
1.234e56
ähnlichen Dinge . Außerdem würde mich interessieren, wie Sie herausfinden würden, dass dies99999999999999999999e99999999999999999999
keine Zahl ist. Der Versuch, es zu analysieren, findet es schnell heraus.Nur Mimic C #
In C # gibt es zwei verschiedene Funktionen, die das Parsen von Skalarwerten handhaben:
float.parse ():
Hinweis: Wenn Sie sich fragen, warum ich die Ausnahme in einen TypeError geändert habe, finden Sie hier die Dokumentation .
float.try_parse ():
Hinweis: Sie möchten den booleschen Wert "False" nicht zurückgeben, da dies immer noch ein Werttyp ist. Keiner ist besser, weil er auf einen Fehler hinweist. Wenn Sie etwas anderes wollen, können Sie den Parameter fail natürlich nach Belieben ändern.
Um float um 'parse ()' und 'try_parse ()' zu erweitern, müssen Sie die 'float'-Klasse monkeypatchen, um diese Methoden hinzuzufügen.
Wenn Sie bereits vorhandene Funktionen respektieren möchten, sollte der Code wie folgt aussehen:
SideNote: Ich persönlich bevorzuge es Monkey Punching zu nennen, weil es sich anfühlt, als würde ich die Sprache missbrauchen, wenn ich das mache, aber YMMV.
Verwendungszweck:
Und der große Weise Pythonas sagte zu dem Heiligen Stuhl Sharpisus: "Alles, was du tun kannst, kann ich besser machen; ich kann alles besser machen als du."
quelle
!
anstelle von istnot
möglicherweise ein kleiner Fehler, aber Sie können demfloat
in CPython integrierten Attribut definitiv keine Attribute zuweisen .Für Zeichenfolgen von Nicht-Zahlen
try: except:
ist tatsächlich langsamer als reguläre Ausdrücke. Bei Zeichenfolgen mit gültigen Zahlen ist der reguläre Ausdruck langsamer. Die geeignete Methode hängt also von Ihrer Eingabe ab.Wenn Sie feststellen, dass Sie sich in einer Leistungsbindung befinden, können Sie ein neues Drittanbieter-Modul namens Fastnumbers verwenden , das eine Funktion namens isfloat bereitstellt . Vollständige Offenlegung, ich bin der Autor. Ich habe seine Ergebnisse in die folgenden Zeitangaben aufgenommen.
Wie du siehst
try: except:
war schnell für numerische Eingaben, aber sehr langsam für ungültige Eingabenfastnumbers
gewinnt in beiden Fällenquelle
prep_code_basis
undprep_code_re_method
hätte meinen Fehler verhindert.isfloat
Funktion?str(s).strip('-').replace('.','',1).isdigit()
ist ungefähr 10x langsamer!Ich weiß, dass dies besonders alt ist, aber ich würde eine Antwort hinzufügen, von der ich glaube, dass sie die Informationen abdeckt, die in der Antwort mit der höchsten Abstimmung fehlen und die für jeden, der dies findet, sehr wertvoll sein könnte:
Verbinden Sie sie für jede der folgenden Methoden mit einer Zählung, wenn Sie eine Eingabe benötigen, die akzeptiert werden soll. (Angenommen, wir verwenden vokale Definitionen von ganzen Zahlen anstelle von 0-255 usw.)
x.isdigit()
funktioniert gut, um zu überprüfen, ob x eine ganze Zahl ist.x.replace('-','').isdigit()
funktioniert gut, um zu überprüfen, ob x negativ ist. (Check - in erster Position)x.replace('.','').isdigit()
funktioniert gut, um zu überprüfen, ob x eine Dezimalzahl ist.x.replace(':','').isdigit()
funktioniert gut, um zu überprüfen, ob x ein Verhältnis ist.x.replace('/','',1).isdigit()
funktioniert gut, um zu überprüfen, ob x ein Bruch ist.quelle
x.replace('/','',1).isdigit()
oder anderweitig Daten wie den 07.04.2017 als Zahlen falsch interpretiert würden.Diese Antwort enthält eine schrittweise Anleitung mit Beispielfunktionen zum Auffinden der Zeichenfolge:
Überprüfen Sie, ob die Zeichenfolge eine positive Ganzzahl ist
Sie können verwenden
str.isdigit()
, um zu überprüfen, ob die angegebene Zeichenfolge eine positive Ganzzahl ist.Beispielergebnisse:
Überprüfen Sie, ob der String positiv / negativ ist - Ganzzahl / Gleitkomma
str.isdigit()
Gibt zurück,False
wenn die Zeichenfolge eine negative Zahl oder eine Gleitkommazahl ist. Zum Beispiel:Wenn Sie auch nach negativen Ganzzahlen
float
suchen möchten, können Sie eine benutzerdefinierte Funktion schreiben, um Folgendes zu überprüfen:Probelauf:
Verwerfen Sie "NaN" -Strings (keine Zahlen), während Sie nach Zahlen suchen
Die obigen Funktionen werden
True
für die Zeichenfolge "NAN" (keine Zahl) zurückgegeben, da es sich bei Python um einen gültigen Float handelt, der darstellt, dass es sich nicht um eine Zahl handelt. Zum Beispiel:Um zu überprüfen, ob die Nummer "NaN" ist, können Sie Folgendes verwenden
math.isnan()
:Wenn Sie keine zusätzliche Bibliothek importieren möchten, um dies zu überprüfen, können Sie sie einfach überprüfen, indem Sie sie mit sich selbst vergleichen
==
. Python kehrt zurück,False
wennnan
float mit sich selbst verglichen wird. Zum Beispiel:Daher oben Funktion
is_number
kann zurückkehren werden aktualisiertFalse
für"NaN"
wie:Probelauf:
PS: Jede Operation für jede Prüfung in Abhängigkeit von der Art der Nummer bringt zusätzlichen Aufwand mit sich. Wählen Sie die
is_number
Funktionsversion, die Ihren Anforderungen entspricht.quelle
Das Casting in Float und das Abfangen von ValueError ist wahrscheinlich der schnellste Weg, da float () genau dafür gedacht ist. Alles andere, was das Parsen von Zeichenfolgen erfordert (regulärer Ausdruck usw.), ist wahrscheinlich langsamer, da es nicht für diesen Vorgang optimiert ist. Meine $ 0,02.
quelle
Sie können Unicode-Zeichenfolgen verwenden. Sie haben eine Methode, um genau das zu tun, was Sie wollen:
Oder:
http://www.tutorialspoint.com/python/string_isnumeric.htm
http://docs.python.org/2/howto/unicode.html
quelle
s.isdecimal()
prüft, ob dies
Zeichenfolge eine nicht negative Ganzzahl ist.s.isnumeric()
Enthält Zeichen, dieint()
ablehnen.Ich wollte sehen, welche Methode am schnellsten ist. Insgesamt lieferte die
check_replace
Funktion die besten und beständigsten Ergebnisse . Die schnellsten Ergebnisse wurden von dercheck_exception
Funktion erzielt , jedoch nur, wenn keine Ausnahme ausgelöst wurde. Dies bedeutet, dass der Code am effizientesten ist, der Aufwand für das Auslösen einer Ausnahme jedoch recht hoch ist.Bitte beachten Sie, dass die Überprüfung auf eine erfolgreiche Besetzung die einzige Methode ist, die genau ist. Dies funktioniert beispielsweise,
check_exception
aber die beiden anderen Testfunktionen geben False für einen gültigen Float zurück:Hier ist der Benchmark-Code:
Hier sind die Ergebnisse mit Python 2.7.10 auf einem 2017 MacBook Pro 13:
Hier sind die Ergebnisse mit Python 3.6.5 auf einem 2017 MacBook Pro 13:
Hier sind die Ergebnisse mit PyPy 2.7.13 auf einem 2017 MacBook Pro 13:
quelle
Wenn man also alles zusammenfasst und nach Nan, Unendlichkeit und komplexen Zahlen sucht (es scheint, dass sie mit j angegeben sind, nicht mit i, dh 1 + 2j), ergibt sich Folgendes:
quelle
Die Eingabe kann wie folgt sein:
a="50"
b=50
c=50.1
d="50.1"
1-Allgemeine Eingabe:
Die Eingabe dieser Funktion kann alles sein!
Findet, ob die angegebene Variable numerisch ist. Numerische Zeichenfolgen bestehen aus einem optionalen Vorzeichen, einer beliebigen Anzahl von Ziffern, einem optionalen Dezimalteil und einem optionalen Exponentialteil. Somit ist + 0123.45e6 ein gültiger numerischer Wert. Hexadezimale (zB 0xf4c3b00c) und binäre (zB 0b10100111001) Notationen sind nicht zulässig.
is_numeric Funktion
Prüfung:
is_float Funktion
Findet, ob die angegebene Variable float ist. float Strings bestehen aus optionalem Vorzeichen, beliebig vielen Ziffern, ...
Prüfung:
Was ist Ast ?
2- Wenn Sie sicher sind, dass der Inhalt der Variablen String ist :
Verwenden Sie die Methode str.isdigit ()
3-Numerische Eingabe:
int-Wert erkennen:
Schwimmer erkennen:
quelle
ast
"?Ich habe einen Geschwindigkeitstest gemacht. Nehmen wir an, wenn die Zeichenfolge wahrscheinlich eine Zahl ist, ist die Try / Except- Strategie die schnellstmögliche. Wenn die Zeichenfolge dies ist keine Zahl ist und Sie an einer Ganzzahlprüfung interessiert sind , lohnt es sich, einen Test durchzuführen (isdigit plus Überschrift) '-'). Wenn Sie die Float-Nummer überprüfen möchten , müssen Sie den Try / Except-Code ohne Escape verwenden.
quelle
Ich musste feststellen, ob ein String in grundlegende Typen umgewandelt wurde (float, int, str, bool). Nachdem ich im Internet nichts gefunden habe, habe ich Folgendes erstellt:
Beispiel
Sie können den Typ erfassen und verwenden
quelle
RyanN schlägt vor
Dies funktioniert jedoch nicht ganz, da bei ausreichend großen Floats
x-1 == x
true zurückgegeben wird. Zum Beispiel,2.0**54 - 1 == 2.0**54
quelle
Ich denke, Ihre Lösung ist in Ordnung, aber es gibt eine korrekte Regexp-Implementierung.
Es scheint eine Menge Regexp-Hass gegen diese Antworten zu geben, was ich für ungerechtfertigt halte. Regexps können einigermaßen sauber und korrekt und schnell sein. Es hängt wirklich davon ab, was Sie versuchen zu tun. Die ursprüngliche Frage war, wie Sie "überprüfen können, ob eine Zeichenfolge als Zahl (float) dargestellt werden kann" (gemäß Ihrem Titel). Vermutlich möchten Sie den numerischen / Gleitkommawert verwenden, sobald Sie überprüft haben, ob er gültig ist. In diesem Fall ist Ihr Versuch / Ihre Ausnahme sehr sinnvoll. Wenn Sie jedoch aus irgendeinem Grund nur überprüfen möchten, ob eine Zeichenfolge eine Zahl istdann funktioniert ein Regex auch gut, aber es ist schwer, richtig zu werden. Ich denke, die meisten bisherigen Regex-Antworten analysieren beispielsweise Strings nicht richtig ohne einen ganzzahligen Teil (wie ".7"), der für Python ein Float ist. Und das ist etwas schwierig in einem einzelnen regulären Ausdruck zu überprüfen, bei dem der Bruchteil nicht benötigt wird. Ich habe zwei Regex eingefügt, um dies zu zeigen.
Es wirft die interessante Frage auf, was eine "Zahl" ist. Fügen Sie "inf" hinzu, das als Float in Python gültig ist? Oder fügen Sie Zahlen hinzu, die "Zahlen" sind, aber möglicherweise nicht in Python dargestellt werden können (z. B. Zahlen, die größer als das Float-Maximum sind).
Es gibt auch Unklarheiten bei der Analyse von Zahlen. Was ist zum Beispiel mit "--20"? Ist das eine "Zahl"? Ist dies eine legale Art, "20" darzustellen? Mit Python können Sie "var = --20" ausführen und auf 20 setzen (obwohl dies wirklich darauf zurückzuführen ist, dass es als Ausdruck behandelt wird), aber float ("- 20") funktioniert nicht.
Wie auch immer, ohne weitere Informationen, hier ist ein regulärer Ausdruck, von dem ich glaube, dass er alle Ints abdeckt und schwebt, während Python sie analysiert .
Einige Beispieltestwerte:
Das Ausführen des Benchmarking-Codes in der Antwort von @ ron-reiter zeigt, dass dieser reguläre Ausdruck tatsächlich schneller als der normale reguläre Ausdruck ist und schlechte Werte viel schneller verarbeitet als die Ausnahme, was sinnvoll ist. Ergebnisse:
quelle
quelle
1e6
, eine Zahl darzustellen?Hier ist meine einfache Art, es zu tun. Angenommen, ich durchlaufe einige Zeichenfolgen und möchte sie einem Array hinzufügen, wenn sich herausstellt, dass es sich um Zahlen handelt.
Ersetzen Sie myvar.apppend durch eine beliebige Operation, die Sie mit der Zeichenfolge ausführen möchten, wenn sich herausstellt, dass es sich um eine Zahl handelt. Die Idee ist, zu versuchen, eine float () -Operation zu verwenden und den zurückgegebenen Fehler zu verwenden, um zu bestimmen, ob die Zeichenfolge eine Zahl ist oder nicht.
quelle
Ich habe auch die von Ihnen erwähnte Funktion verwendet, aber bald stelle ich fest, dass Zeichenfolgen wie "Nan", "Inf" und ihre Variation als Zahl betrachtet werden. Daher schlage ich vor, dass Sie eine verbesserte Version Ihrer Funktion haben, die bei dieser Art von Eingabe false zurückgibt und "1e3" -Varianten nicht fehlschlägt:
quelle
Dieser Code behandelt die Exponenten, Gleitkommazahlen und Ganzzahlen ohne Verwendung von Regex.
quelle
Benutzerhilfefunktion:
dann
quelle
Sie können die Ausnahmetechnik auf nützliche Weise verallgemeinern, indem Sie nützlichere Werte als True und False zurückgeben. Diese Funktion setzt beispielsweise Anführungszeichen um runde Zeichenfolgen, lässt jedoch Zahlen in Ruhe. Welches ist genau das, was ich für einen schnellen und schmutzigen Filter brauchte, um einige Variablendefinitionen für R zu erstellen.
quelle
Ich habe an einem Problem gearbeitet, das mich zu diesem Thread geführt hat, nämlich wie man eine Sammlung von Daten auf intuitivste Weise in Zeichenfolgen und Zahlen konvertiert. Nachdem ich den Originalcode gelesen hatte, stellte ich fest, dass das, was ich brauchte, in zweierlei Hinsicht anders war:
1 - Ich wollte ein ganzzahliges Ergebnis, wenn die Zeichenfolge eine Ganzzahl darstellt
2 - Ich wollte, dass eine Zahl oder ein String-Ergebnis in eine Datenstruktur passt
Also habe ich den Originalcode angepasst, um diese Ableitung zu erzeugen:
quelle
Versuche dies.
quelle
is_number('10')
quelle