Wie kann ich am besten überprüfen, ob eine Zeichenfolge in Python als Zahl dargestellt werden kann?
Die Funktion, die ich momentan habe, ist:
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
Was nicht nur hässlich und langsam ist, scheint klobig zu sein. Ich habe jedoch keine bessere Methode gefunden, weil der Aufruf von float
in der Hauptfunktion noch schlechter ist.
Was nicht nur hässlich und langsam ist
Ich würde beide bestreiten.
Ein Regex oder ein anderes String-Parsing wäre hässlicher und langsamer.
Ich bin mir nicht sicher, ob etwas schneller sein könnte als das oben Genannte. Es ruft die Funktion auf und kehrt zurück. Try/Catch verursacht keinen großen Aufwand, da die häufigste Ausnahme ohne umfangreiche Suche nach Stack-Frames abgefangen wird.
Das Problem ist, dass jede numerische Konvertierungsfunktion zwei Arten von Ergebnissen hat
C (als Beispiel) hackt einige Möglichkeiten. Python legt es klar und explizit dar.
Ich denke, Ihr Code dafür ist perfekt.
Wenn Sie nach Parsing-Werten (positiven, vorzeichenlosen) Ganzzahlen anstelle von Gleitkommazahlen suchen, können Sie die Funktion isdigit()
für Stringobjekte verwenden.
>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False
Es gibt auch etwas auf Unicode-Strings, mit dem ich nicht vertraut bin Unicode - Ist dezimal/dezimal
TL; DR Die beste Lösung ist s.replace('.','',1).isdigit()
Ich habe einige Benchmarks die verschiedenen Ansätze verglichen
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()
Wenn der String keine Zahl ist, ist der Exceptor-Block ziemlich langsam. Noch wichtiger ist jedoch, dass die Try-Except-Methode der einzige Ansatz ist, der wissenschaftliche Notationen korrekt verarbeitet.
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__)
Float-Notation ".1234" wird nicht unterstützt von:
- 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__)
Die wissenschaftliche Notation "1.000000e + 50" wird nicht unterstützt von:
- is_number_regex
- is_number_repl_isdigit
Wissenschaftliche Notation "1e50" wird nicht unterstützt von:
- 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)))
wo die folgenden Funktionen getestet wurden
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()
Es gibt eine Ausnahme, die Sie berücksichtigen möchten: Die Zeichenfolge "NaN"
Wenn Sie möchten, dass is_number für "NaN" FALSE zurückgibt, funktioniert dieser Code nicht, da Python es in eine Zahl konvertiert, die keine Zahl ist (sprechen Sie über Identitätsprobleme):
>>> float('NaN')
nan
Ansonsten sollte ich mich eigentlich für den Code bedanken, den ich jetzt ausgiebig verwende. :)
G.
wie wäre es damit:
'3.14'.replace('.','',1).isdigit()
die nur dann wahr zurückgeben wird, wenn es eine oder keine '.' in der Ziffernfolge.
'3.14.5'.replace('.','',1).isdigit()
wird falsch zurückkehren
edit: habe gerade einen weiteren Kommentar gesehen ... Hinzufügen einer .replace(badstuff,'',maxnum_badstuff)
für andere Fälle kann gemacht werden. Wenn Sie salzige und nicht willkürliche Gewürze abgeben (ref: xkcd # 974 ), ist dies gut: P
Nachdem Alfe darauf hingewiesen hat, müssen Sie nicht mehr nach Float suchen, da komplexe Griffe beide sind:
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 müssen Sie möglicherweise auch nach komplexen Zahlen suchen (z. B. 1 + 2i), die nicht durch einen Float 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
Was nicht nur hässlich und langsam ist, scheint klobig zu sein.
Es mag gewöhnungsbedürftig sein, aber dies ist die Pythonic-Methode. Wie bereits erwähnt, sind die Alternativen schlechter. Es gibt aber noch einen weiteren Vorteil, wenn man so vorgeht: Polymorphismus.
Die zentrale Idee hinter dem Entenschreiben lautet: "Wenn es wie eine Ente geht und spricht, dann ist es eine Ente." Was ist, wenn Sie entscheiden, dass Sie eine Zeichenfolge in einer Unterklasse definieren müssen, damit Sie ändern können, wie Sie feststellen, ob etwas in einen Float konvertiert werden kann? Oder wenn Sie sich entscheiden, ein anderes Objekt vollständig zu testen? Sie können diese Schritte ausführen, 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 sich entschieden auf der Enten-Seite der Gleichung befindet und Sie müssen sich wahrscheinlich an diese Syntax gewöhnen, wenn Sie vorhaben, viel in Python zu programmieren (was aber nicht bedeutet du musst es natürlich mögen).
Eine andere Sache, die Sie vielleicht in Betracht ziehen sollten: Python ist im Vergleich zu vielen anderen Sprachen (etwa 30x schneller als .Net) ziemlich schnell beim Werfen und Erfassen 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 muss ich mich nicht zu sehr um die Leistungsaspekte dieses Codes kümmern, bis Sie ein erhebliches Problem feststellen.
Für int
verwenden Sie folgendes:
>>> "1221323".isdigit()
True
Aber für float
brauchen wir ein paar Tricks ;-). Jede Float-Nummer 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 fügen Sie einfach lstrip()
hinzu:
>>> '-12'.lstrip('-')
'12'
Und jetzt bekommen wir einen universellen Weg:
>>> '-12.34'.lstrip('-').replace('.','',1).isdigit()
True
>>> '.-234'.lstrip('-').replace('.','',1).isdigit()
False
In C # gibt es zwei verschiedene Funktionen, die die Analyse von Skalarwerten durchführen:
float.parse ():
def parse(string):
try:
return float(string)
except Exception:
throw TypeError
Anmerkung: Wenn Sie sich fragen, warum ich die Ausnahme in einen TypeError geändert habe, dann hier ist die Dokumentation .
float.try_parse ():
def try_parse(string, fail=None):
try:
return float(string)
except Exception:
return fail;
Hinweis: Sie möchten nicht den booleschen Wert 'False' zurückgeben, da dies immer noch ein Werttyp ist. Keiner ist besser, da er auf einen Fehler hinweist. Wenn Sie etwas anderes möchten, können Sie den Parameter 'Fail' natürlich beliebig ändern .
Um Float zu erweitern, um 'parse ()' und 'try_parse ()' einzuschließen, müssen Sie die 'float'-Klasse monkeypatchen, um diese Methoden hinzuzufügen.
Wenn Sie bereits vorhandene Funktionen berücksichtigen möchten, sollte der Code wie folgt aussehen:
def monkey_patch():
if(!hasattr(float, 'parse')):
float.parse = parse
if(!hasattr(float, 'try_parse')):
float.try_parse = try_parse
SideNote: Ich persönlich ziehe es vor, Monkey Punching zu nennen, weil es sich anfühlt, als würde ich die Sprache missbrauchen, wenn ich dies tue, außer YMMV.
Verwendungszweck:
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
Und der große Weise Pythonas sagte zu Sharpisus des Heiligen Stuhls: "Alles, was Sie tun können, kann ich besser; ich kann etwas besser als Sie."
Für Zeichenfolgen, die keine Zahlen sind, ist try: except:
tatsächlich langsamer als reguläre Ausdrücke. Für Zeichenfolgen gültiger Zahlen ist der reguläre Ausdruck langsamer. Die geeignete Methode hängt also von Ihrer Eingabe ab.
Wenn Sie feststellen, dass Sie sich in einem Performance-Bind 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 die Ergebnisse in die Timings unten 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 du siehst
try: except:
war schnell für die numerische Eingabe, aber für eine ungültige Eingabe sehr langsamfastnumbers
gewinnt in beiden FällenIch 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 am besten bewerteten Antwort fehlen, die für jeden, der dies findet, sehr wertvoll sein könnten:
Verbinden Sie sie für jede der folgenden Methoden mit einer Zählung, wenn Eingaben akzeptiert werden müssen. (Angenommen, wir verwenden stimmliche Definitionen von Ganzzahlen 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 prüfen, ob x ein negatives Ergebnis ist.
x.replace('.','').isdigit()
funktioniert gut, um zu prüfen, ob x eine Dezimalzahl ist.
x.replace(':','').isdigit()
funktioniert gut, um zu prüfen, ob x ein Verhältnis ist.
x.replace('/','',1).isdigit()
funktioniert gut, um zu prüfen, ob x ein Bruch ist.
Sie können Unicode-Zeichenfolgen verwenden. Sie haben eine Methode, um genau das zu tun, was Sie möchten:
>>> s = u"345"
>>> s.isnumeric()
True
Oder:
>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True
Das Floaten und Fangen von ValueError ist wahrscheinlich der schnellste Weg, da float () genau dafür gedacht ist. Alle anderen Elemente, für die eine Zeichenfolgenanalyse erforderlich ist (Regex usw.), sind wahrscheinlich langsamer, da sie für diesen Vorgang nicht geeignet sind. Meine $ 0,02.
Ich wollte sehen, welche Methode am schnellsten ist. Insgesamt wurden die besten und konsistentesten Ergebnisse mit der Funktion check_replace
erzielt. Die schnellsten Ergebnisse wurden von der check_exception
-Funktion geliefert, jedoch nur, wenn keine Ausnahme ausgelöst wurde. Dies bedeutet, dass der Code der effizienteste ist, der Aufwand für das Auslösen einer Ausnahme jedoch recht groß ist.
Bitte beachten Sie, dass die Prüfung auf eine erfolgreiche Besetzung die einzige Methode ist, die genau ist. Dies funktioniert beispielsweise mit check_exception
. Die anderen beiden Testfunktionen geben jedoch False für ein gültiges Float zurück:
huge_number = float('1e+100')
Hier ist der Benchmark-Code:
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))
Hier sind die Ergebnisse mit Python 2.7.10 auf einem MacBook Pro 13 von 2017:
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
Hier sind die Ergebnisse mit Python 3.6.5 auf einem MacBook Pro 13 von 2017:
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
Hier sind die Ergebnisse mit PyPy 2.7.13 auf einem MacBook Pro 13 von 2017:
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
Diese Antwort enthält eine Schritt-für-Schritt-Anleitung mit Funktionen zum Auffinden der Zeichenfolge:
Sie können mit str.isdigit()
prüfen, ob die angegebene Zeichenfolge positive integer ist.
Beispielergebnisse:
# For digit
>>> '1'.isdigit()
True
>>> '1'.isalpha()
False
str.isdigit()
gibt False
zurück, wenn die Zeichenfolge eine negative-Nummer oder eine Float-Nummer ist. Zum Beispiel:
# returns `False` for float
>>> '123.3'.isdigit()
False
# returns `False` for negative number
>>> '-123'.isdigit()
False
Wenn Sie auch nach negativen Ganzzahlen und float
suchen möchten, können Sie eine benutzerdefinierte Funktion schreiben, um dies zu prü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
Probelauf:
>>> 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
Die obigen Funktionen geben True
für die Zeichenfolge "NAN" (Keine Zahl) zurück, da es sich bei Python um einen gültigen Float handelt, der darstellt, dass es keine Zahl ist. Zum Beispiel:
>>> is_number('NaN')
True
Um zu prüfen, ob die Nummer "NaN" ist, können Sie 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 sie einfach überprüfen, indem Sie sie mit ==
mit sich selbst vergleichen. Python gibt False
zurück, wenn nan
float mit sich selbst verglichen wird. Zum Beispiel:
# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False
Daher kann über function is_number
aktualisiert werden, um False
für "NaN"
als zurückzugeben:
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
Probelauf:
>>> 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: Jede Operation für jede Prüfung, abhängig von der Art der Nummer, ist mit zusätzlichem Aufwand verbunden. Wählen Sie die Version der is_number
-Funktion, die Ihrer Anforderung entspricht.
Nehmen wir an, Sie haben Ziffern in der Zeichenfolge . Str = "100949" Und Sie möchten prüfen, ob nur Zahlen vorhanden sind
if str.isdigit():
returns TRUE or FALSE
ansonsten funktioniert Ihre Methode hervorragend, um das Vorkommen einer Ziffer in einer Zeichenfolge zu finden.
Um es zusammenzufassen: Wenn Sie nach Nan, Unendlich und komplexen Zahlen suchen (es scheint, als würden sie mit j angegeben, nicht mit i, d. H. 1 + 2j), ergibt sich
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
Ihr Code sieht gut aus für mich.
Vielleicht denken Sie, dass der Code wegen Ausnahmen "klobig" ist? Beachten Sie, dass Python-Programmierer aufgrund ihrer geringen Leistungseinbußen meist großzügig Ausnahmen verwenden, wenn sie die Lesbarkeit von Code verbessern.
Ich musste feststellen, ob eine Zeichenfolge in Basistypen (float, int, str, bool) umgewandelt wird. Nachdem ich im Internet nichts gefunden habe, habe ich folgendes erstellt:
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)
Beispiel
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
Sie können den Typ erfassen und verwenden
s = "6.0"
type_ = str_to_type(s) # float
f = type_(s)
Ich habe einen Geschwindigkeitstest gemacht. Nehmen wir an, wenn die Zeichenfolge wahrscheinlich eine Zahl ist, ist die Strategie try/except die schnellste. Wenn die Zeichenfolge ist ist nicht wahrscheinlich um eine Zahl zu sein nd Sie interessieren sich für Integer Überprüfen Sie, ob es sich lohnt, 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.
Die Eingabe kann wie folgt sein:
a="50"
b=50
c=50.1
d="50.1"
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. Hexadezimal-Schreibweise (z. B. 0xf4c3b00c) und binäre Schreibweise (z. B. 0b10100111001) ist nicht zulässig.
is_numeric Funktion
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
prüfung:
>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True
is_float -Funktion
Findet, ob die angegebene Variable float ist. Float-Strings bestehen aus optionalen Zeichen, einer beliebigen Anzahl von Ziffern, ...
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
prüfung:
>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True
was ist ast ?
verwenden Sie str.isdigit () Methode
>>> 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
int-Wert ermitteln:
>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>>
Float erkennen:
>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True
RyanN schlägt vor
Wenn Sie für NaN und Inf False zurückgeben möchten, ändern Sie die Zeile in x = float (s); return (x == x) und (x - 1! = x). Dies sollte für alle Floats mit Ausnahme von Inf und NaN True zurückgeben
Dies funktioniert jedoch nicht ganz, denn x-1 == x
gibt für ausreichend große Floats true zurück. Zum Beispiel 2.0**54 - 1 == 2.0**54
Ich habe auch die von Ihnen erwähnte Funktion verwendet, aber bald bemerke ich, dass Strings als "Nan", "Inf" und deren Variation als Zahl betrachtet werden. Ich schlage also vor, Sie haben eine verbesserte Version Ihrer Funktion, die bei dieser Art der Eingabe false zurückgibt und "1e3" -Varianten nicht versagt:
def is_float(text):
try:
float(text)
# check for nan/infinity etc.
if text.isalpha():
return False
return True
except ValueError:
return False
Sie können die Ausnahmetechnik sinnvoll verallgemeinern, indem Sie nützlichere Werte als "Wahr" und "Falsch" zurückgeben. Diese Funktion setzt beispielsweise Anführungszeichen in runde Zeichenketten, lässt aber Zahlen allein. Genau das brauchte ich für einen schnellen und schmutzigen Filter, um einige Variablendefinitionen für R zu erstellen.
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:]), ')'
Versuche dies.
def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False
Benutzerhilfefunktion:
def if_ok(fn, string):
try:
return fn(string)
except Exception as e:
return None
dann
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)])
Wenn Sie wissen möchten, ob die Zeichenfolge complete als Zahl dargestellt werden kann, möchten Sie einen Regex verwenden (oder den Float zurück in eine Zeichenfolge konvertieren und mit der Quellzeichenfolge vergleichen das ist nicht sehr schnell).
Ich denke, deine Lösung ist in Ordnung.
Trotzdem gibt es eine Menge Hass gegen diese Antworten, die ich für ungerechtfertigt halte. Regexps können einigermaßen sauber, korrekt und schnell sein. Es hängt wirklich davon ab, was Sie versuchen. 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/float-Wert verwenden, sobald Sie überprüft haben, ob er gültig ist. In diesem Fall ist Ihr try/except sehr sinnvoll. Aber wenn Sie aus irgendeinem Grund nur prüfen möchten, ob ein String eine Zahl ist, funktioniert auch ein regulärer Ausdruck, aber es ist schwierig, ihn zu korrigieren. Ich denke, die meisten der bisherigen Regex-Antworten analysieren beispielsweise Strings ohne einen ganzzahligen Teil (wie ".7"), der für Python ein Float ist, nicht richtig. Und es ist etwas schwierig, in einem einzelnen Regex nach dem Bruchteil zu suchen, der nicht benötigt wird. Ich habe zwei reguläre Ausdrücke eingefügt, um dies zu zeigen.
Es wirft die interessante Frage auf, was eine "Zahl" ist. Enthalten Sie "inf", das als Float in Python gültig ist? Oder schließen Sie Zahlen ein, die "Zahlen" sind, aber möglicherweise nicht in Python dargestellt werden können (z. B. Zahlen, die größer sind als das Float-Maximum).
Es gibt auch Unklarheiten, wie Sie Zahlen analysieren. Was ist zum Beispiel mit "--20"? Ist das eine "Nummer"? Ist dies eine legale Möglichkeit, "20" darzustellen? In Python können Sie "var = --20" eingeben und auf 20 setzen (obwohl dies in Wirklichkeit 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 und Floats abdeckt wie Python sie parst .
# 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
Einige Beispieltestwerte:
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
Dieser Code behandelt die Exponenten, Gleitkommazahlen und Ganzzahlen, ohne Regex zu verwenden.
return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False
Hier ist meine einfache Art, es zu tun. Nehmen wir an, ich durchsehe einige Zeichenketten und möchte sie zu einem Array hinzufügen, wenn sie Zahlen sind.
try:
myvar.append( float(string_to_check) )
except:
continue
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 festzustellen, ob die Zeichenfolge eine Zahl ist oder nicht.
Ich arbeitete an einem Problem, das mich zu diesem Thread führte, nämlich wie eine Sammlung von Daten auf intuitivste Weise in Strings und Zahlen umgewandelt werden kann. Nachdem ich den Originalcode gelesen hatte, wurde mir klar, dass das, was ich brauchte, in zweierlei Hinsicht anders war:
1 - Ich wollte ein ganzzahliges Ergebnis, wenn die Zeichenfolge eine ganze Zahl darstellt
2 - Ich wollte, dass eine Zahl oder ein String-Ergebnis in eine Datenstruktur eingefügt wird
also habe ich den Originalcode angepasst, um diese Ableitung zu erzeugen:
def string_or_number(s):
try:
z = int(s)
return z
except ValueError:
try:
z = float(s)
return z
except ValueError:
return s
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