zulassen - python ziffern einer zahl




Wie überprüfe ich, ob eine Zeichenfolge eine Zahl(Float) ist? (20)

Was ist die beste Möglichkeit zu überprüfen, ob eine Zeichenfolge in Python als Zahl dargestellt werden kann?

Die Funktion, die ich momentan gerade habe, ist:

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

Was nicht nur hässlich und langsam ist, wirkt klobig. Ich habe jedoch keine bessere Methode gefunden, weil float in der Hauptfunktion noch schlimmer ist.


Was nicht nur hässlich und langsam ist, wirkt klobig.

Es kann etwas gewöhnungsbedürftig sein, aber das ist die pythonische Art, es zu tun. Wie bereits erwähnt, sind die Alternativen schlechter. Aber es gibt einen weiteren Vorteil, die Dinge auf diese Weise zu tun: Polymorphismus.

Die zentrale Idee hinter der Eingabe von Enten ist, dass "wenn es wie eine Ente geht und spricht, dann ist es eine Ente." Was ist, wenn Sie sich entschließen, eine Unterklasse zu erstellen, damit Sie ändern können, wie Sie bestimmen, ob etwas in eine Gleitkomma umgewandelt 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 durch die Verwendung von Schnittstellen. Ich werde die Analyse speichern, welche Lösung besser für einen anderen Thread ist. Der Punkt ist jedoch, dass Python entschieden auf der Duck-Typ-Seite der Gleichung ist, und Sie werden sich wahrscheinlich an Syntax wie diese gewöhnen müssen, wenn Sie planen, viel in Python zu programmieren (aber das bedeutet nicht du musst es natürlich mögen).

Eine andere Sache, die Sie vielleicht in Betracht ziehen sollten: Python ist ziemlich schnell im Auswerfen und Abfangen von Ausnahmen im Vergleich zu vielen anderen Sprachen (30x schneller als. NET zum Beispiel). Ach ja, die Sprache selbst gibt sogar Ausnahmen aus, um nicht-außergewöhnliche, normale Programmbedingungen zu kommunizieren (jedes Mal, wenn Sie eine for-Schleife verwenden). Daher mache ich mir keine Gedanken über die Leistungsaspekte dieses Codes, bis Sie ein signifikantes Problem bemerken.


Welches ist nicht nur hässlich und langsam

Ich würde beides bestreiten.

Eine Regex- oder andere String-Analyse wäre hässlicher und langsamer.

Ich bin mir nicht sicher, dass etwas viel schneller sein könnte als das obige. Es ruft die Funktion auf und kehrt zurück. Try / Catch verursacht keinen hohen Overhead, 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

  • Eine Nummer, wenn die Nummer gültig ist
  • Ein Statuscode (z. B. über Fehlernummer) oder eine Ausnahme, um anzuzeigen, dass keine gültige Nummer analysiert werden konnte.

C (als Beispiel) hackt dies auf eine Anzahl von Wegen. Python legt es klar und deutlich dar.

Ich denke, dass dein Code dafür perfekt ist.


Aktualisiert, nachdem Alfe darauf hingewiesen hat, dass Sie nicht separat nach Float suchen müssen.

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

    return True

Früher gesagt: In einigen seltenen Fällen müssen Sie auch nach komplexen Zahlen suchen (zB 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

Das Floaten und Abfangen von ValueError ist wahrscheinlich der schnellste Weg, da float () genau dafür gedacht ist. Alles andere, das das Parsen von Zeichenfolgen (Regex usw.) erfordert, wird wahrscheinlich langsamer sein, da es für diese Operation nicht optimiert ist. Meine $ 0,02.


Diese Antwort bietet Schritt-für-Schritt-Anleitung mit Funktionen mit Beispielen, um die Zeichenfolge zu finden:

  • Positive ganze Zahl
  • Positiv / Negativ - Ganzzahl / Gleitkommazahl
  • Wie man "NaN" (keine Zahl) Zeichenketten wegwirft, während man nach Zahl sucht?

Überprüfen Sie, ob die Zeichenfolge eine positive Ganzzahl ist

Sie können isdigit() , um zu überprüfen, ob die angegebene Zeichenfolge eine positive Ganzzahl ist.

Beispielergebnisse:

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

Überprüfen Sie, ob die Zeichenfolge positiv / negativ ist - Integer / Float

str.isdigit() gibt False wenn die Zeichenfolge eine negative Zahl oder eine str.isdigit() ist. Beispielsweise:

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

Wenn Sie auch nach den negativen Ganzzahlen und float suchen möchten, können Sie eine benutzerdefinierte Funktion schreiben, um Folgendes 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

Beispiellauf:

>>> 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 Sie "NaN" (keine Zahl) Zeichenketten, während Sie nach der Nummer suchen

Die obigen Funktionen geben True für die Zeichenfolge "NAN" (Not a number) zurück, weil es für Python ein gültiger float ist, der eine Zahl darstellt. Beispielsweise:

>>> is_number('NaN')
True

Um zu überprüfen, ob die Nummer "NaN" ist, können Sie math.isnan() wie math.isnan() :

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

>>> math.isnan(nan_num)
True

Oder wenn Sie keine zusätzliche Bibliothek importieren möchten, um dies zu überprüfen, können Sie es einfach überprüfen, indem Sie es mit sich selbst vergleichen, indem Sie == . Python gibt False wenn nan float mit sich selbst verglichen wird. Beispielsweise:

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

Daher kann die obige Funktion is_number aktualisiert werden, um False für "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

Beispiellauf:

>>> 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: Each operation for each check depending on the type of number comes with additional overhead. Choose the version of is_number function which fits your requirement.


Es gibt eine Ausnahme, die Sie berücksichtigen sollten: die Zeichenfolge 'NaN'

Wenn Sie wollen, dass is_number FALSE für 'NaN' zurückgibt, wird dieser Code nicht funktionieren, da Python ihn in seine Darstellung einer Zahl umwandelt, die keine Zahl ist (sprechen Sie über Identitätsprobleme):

>>> float('NaN')
nan

Ansonsten sollte ich Ihnen tatsächlich für den Code danken, den ich jetzt ausgiebig verwende. :)

G.


Ich habe einen Geschwindigkeitstest gemacht. Nehmen wir an, wenn die Zeichenfolge wahrscheinlich eine Zahl ist, ist die try / except- Strategie die schnellste mögliche. Wenn die Zeichenfolge wahrscheinlich keine Zahl ist und Sie Interesse an Integer- Prüfung haben, lohnt es sich, einige Tests (isdigit plus heading) "-"). Wenn Sie Interesse haben, die Float-Nummer zu überprüfen, müssen Sie den try / exception-Code ohne escape verwenden.


Ich musste feststellen, ob eine Zeichenfolge in Basistypen (float, int, str, bool) umgewandelt wurde. Nachdem ich nichts im Internet 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 wollte sehen, welche Methode am schnellsten ist. Insgesamt wurden die besten und konsistentesten Ergebnisse von der Funktion check_replace . Die schnellsten Ergebnisse wurden mit der check_exception Funktion check_exception , allerdings nur, wenn keine Ausnahme ausgelöst wurde - was bedeutet, dass der Code am effizientesten ist, aber der Aufwand für das Auslösen einer Ausnahme ziemlich groß ist.

Bitte beachten Sie, dass die Überprüfung auf eine erfolgreiche Besetzung die einzige Methode ist, die genau ist. Dies funktioniert beispielsweise mit check_exception aber die anderen beiden Testfunktionen geben False für einen gültigen 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 2017 MacBook Pro 13:

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 2017 MacBook Pro 13:

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 2017 MacBook Pro 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

RyanN schlägt vor

Wenn Sie False für NaN und Inf zurückgeben möchten, ändern Sie die Zeile in x = float (s); Rückgabe (x == x) und (x - 1! = x). Dies sollte True für alle Floats außer Inf und NaN zurückgeben

Aber das funktioniert nicht ganz, denn für ausreichend große Floats gibt x-1 == x wahr zurück. Zum Beispiel 2.0**54 - 1 == 2.0**54



Um alles zusammenzufassen, indem man nach Nan, Unendlichkeit und komplexen Zahlen sucht (es scheint, dass sie mit j, nicht mit i, dh 1 + 2j spezifiziert sind), ergibt dies:

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


try: except: für Strings von Nicht-Zahlen try: except: ist eigentlich langsamer als reguläre Ausdrücke. Bei Strings mit gültigen Zahlen ist Regex 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 Modul von fastnumbers namens fastnumbers , das eine Funktion fastnumbers , die isfloat . Vollständige Offenlegung, ich bin der Autor. Ich habe seine Ergebnisse zu den Zeitpunkten unten eingefügt.

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 sehr langsam für eine ungültige Eingabe
  • Regex ist sehr effizient, wenn die Eingabe ungültig ist
  • fastnumbers gewinnt in beiden Fällen

Here's my simple way of doing it. Let's say that I'm looping through some strings and I want to add them to an array if they turn out to be numbers.

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

Replace the myvar.apppend with whatever operation you want to do with the string if it turns out to be a number. The idea is to try to use a float() operation and use the returned error to determine whether or not the string is a number.


I also used the function you mentioned, but soon I notice that strings as "Nan", "Inf" and it's variation are considered as number. So I propose you improved version of your function, that will return false on those type of input and will not fail "1e3" variants:

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

If you want to know if the entire string can be represented as a number you'll want to use a regexp (or maybe convert the float back to a string and compare it to the source string, but I'm guessing that's not very fast).


To check if the input value is a float , you can compare the type of the input to a float

def isFloat(s):
    realFloat = 0.1

    if type(s) == type(realFloat):
        return True
    else:
        return False

Kehrt zurück:

False     # s = 5
True      # s = 1.2345

Die ursprüngliche Post würde tatsächlich zurückkehren Truezu , s = 5da es eine Zahl (integer) und Sie können einen Guss intzu einem floatohne ValueError. Wenn Sie versuchen, zu überprüfen, ob es sich um eine tatsächliche floatZahl und nicht nur um eine Zahl handelt, müssen Sie diesen Fall berücksichtigen.


You can generalize the exception technique in a useful way by returning more useful values than True and False. For example this function puts quotes round strings but leaves numbers alone. Which is just what I needed for a quick and dirty filter to make some variable definitions for 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:]), ')'

You may use regex.

number = raw_input("Enter a number: ")
if re.match(r'^\d+$', number):
    print "It's integer"
    print int(number)
elif re.match(r'^\d+\.\d+$', number):
    print "It's float"
    print float(number)
else:
    print("Please enter a number")




type-conversion