Domanda

Qual è il modo migliore per verificare se una stringa può essere rappresentata come numero in Python?

La funzione che ho attualmente in questo momento è:

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

Il che, non solo è brutto e lento, sembra goffo. Tuttavia non ho trovato un metodo migliore perché chiamare float nella funzione principale è anche peggio.

È stato utile?

Soluzione

  

Il che, non solo è brutto e lento

Controverei entrambi.

Un regex o un altro metodo di analisi delle stringhe sarebbe più brutto e più lento.

Non sono sicuro che qualcosa di molto potrebbe essere più veloce di quanto sopra. Chiama la funzione e ritorna. Try / Catch non introduce molto overhead perché l'eccezione più comune viene rilevata senza una vasta ricerca di frame stack.

Il problema è che qualsiasi funzione di conversione numerica ha due tipi di risultati

  • Un numero, se il numero è valido
  • Un codice di stato (ad es. tramite errno) o un'eccezione per mostrare che non è stato possibile analizzare alcun numero valido.

C (come esempio) aggira questo in diversi modi. Python lo espone in modo chiaro ed esplicito.

Penso che il tuo codice per farlo sia perfetto.

Altri suggerimenti

Nel caso in cui tu stia cercando numeri interi (positivi, non firmati) invece di float, puoi usare isdigit() per gli oggetti stringa.

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

Metodi stringa - <=>: Python2 , Python3

C'è anche qualcosa sulle stringhe Unicode, che non conosco troppo bene Unicode - È decimale / decimale

TL; DR La soluzione migliore è s.replace('.','',1).isdigit()

Ho fatto un po 'di benchmark confrontando i diversi approcci

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

Se la stringa non è un numero, il blocco di eccezione è piuttosto lento. Ma ancora più importante, il metodo try-tranne è l'unico approccio che gestisce correttamente le notazioni scientifiche.

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

Notazione float " .1234 " non è supportato da:
- 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__)

Notazione scientifica " 1.000000e + 50 " non è supportato da:
- is_number_regex
- is_number_repl_isdigit
Notazione scientifica & Quot; 1e50 & Quot; non è supportato da:
- is_number_regex
- is_number_repl_isdigit

EDIT: i risultati del benchmark

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

dove sono state testate le seguenti funzioni

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

 inserisci qui la descrizione dell

C'è un'eccezione che potresti voler prendere in considerazione: la stringa 'NaN'

Se vuoi che is_number restituisca FALSE per 'NaN' questo codice non funzionerà poiché Python lo converte nella sua rappresentazione di un numero che non è un numero (parla di problemi di identità):

>>> float('NaN')
nan

Altrimenti, dovrei davvero ringraziarti per il pezzo di codice che ora uso ampiamente. :)

G.

che ne dici di questo:

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

che tornerà vero solo se c'è uno o nessun '.' nella stringa di cifre.

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

restituirà false

modifica: ho appena visto un altro commento ... è possibile aggiungere un .replace(badstuff,'',maxnum_badstuff) per altri casi. se stai passando sale e condimenti non arbitrari (rif: xkcd # 974 ) questo andrà bene: P

Aggiornato dopo che Alfe ha sottolineato che non è necessario controllare separatamente il float poiché entrambi i gestori sono complessi:

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

    return True

Precedentemente detto: in alcuni rari casi potresti anche dover verificare la presenza di numeri complessi (ad es. 1 + 2i), che non possono essere rappresentati da un float:

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
  

Il che, non solo è brutto e lento, sembra goffo.

Potrebbe volerci un po 'di tempo per abituarsi, ma questo è il modo pitonico di farlo. Come è già stato sottolineato, le alternative sono peggiori. Ma c'è un altro vantaggio nel fare le cose in questo modo: il polimorfismo.

L'idea centrale dietro la tipizzazione delle anatre è che " se cammina e parla come un'anatra, allora è un'anatra. " Che cosa succede se decidi che devi sottoclassare la stringa in modo da poter cambiare il modo in cui determini se qualcosa può essere convertito in un float? O se decidessi di provare completamente qualche altro oggetto? Puoi fare queste cose senza dover cambiare il codice sopra.

Altre lingue risolvono questi problemi usando le interfacce. Salverò l'analisi di quale soluzione è migliore per un altro thread. Il punto, tuttavia, è che python è decisamente dalla parte dell'equazione digitando l'anatra, e probabilmente dovrai abituarti a una sintassi come questa se pensi di fare molta programmazione in Python (ma ciò non significa devi piacerti, ovviamente).

Un'altra cosa che potresti voler prendere in considerazione: Python è piuttosto veloce nel lanciare e catturare eccezioni rispetto a molte altre lingue (30 volte più veloce di .Net per esempio). Diamine, la stessa lingua genera anche eccezioni per comunicare condizioni di programma normali non eccezionali (ogni volta che usi un ciclo for). Pertanto, non mi preoccuperei troppo degli aspetti prestazionali di questo codice fino a quando non noterai un problema significativo.

Per int utilizzare questo:

>>> "1221323".isdigit()
True

Ma per float abbiamo bisogno di alcuni trucchi ;-). Ogni numero float ha un punto ...

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

Anche per i numeri negativi basta aggiungere lstrip():

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

E ora otteniamo un modo universale:

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

Solo Mimic C #

In C # ci sono due diverse funzioni che gestiscono l'analisi dei valori scalari:

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

float.parse ():

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

Nota: se ti stai chiedendo perché ho cambiato l'eccezione in TypeError, ecco la documentazione .

float.try_parse ():

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

Nota: non si desidera restituire il booleano 'False' perché è ancora un tipo di valore. Nessuno è migliore perché indica un errore. Naturalmente, se vuoi qualcosa di diverso, puoi cambiare il parametro fail in quello che vuoi.

Per estendere float per includere 'parse ()' e 'try_parse ()' devi aggiungere la classe 'float' per aggiungere questi metodi.

Se vuoi rispettare le funzioni preesistenti, il codice dovrebbe essere qualcosa del tipo:

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

Nota a margine: Personalmente preferisco chiamarlo Monkey Punching perché mi sembra di abusare della lingua quando lo faccio, ma YMMV.

Utilizzo:

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

E il grande Saggio Pitone disse alla Santa Sede Sharpisus, " Tutto ciò che puoi fare, posso fare di meglio; Posso fare qualcosa di meglio di te. & Quot;

Per le stringhe di non numeri, try: except: è in realtà più lento delle espressioni regolari. Per stringhe di numeri validi, regex è più lento. Quindi, il metodo appropriato dipende dal tuo input.

Se scopri di essere in un legame prestazionale, puoi utilizzare un nuovo modulo di terze parti chiamato fastnumbers che fornisce una funzione chiamata isfloat . Divulgazione completa, sono l'autore. Ho incluso i suoi risultati nei tempi seguenti.


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

Come puoi vedere

  • fastnumbers è stato veloce per l'input numerico ma molto lento per un input non valido
  • regex è molto efficiente quando l'input non è valido
  • <=> vince in entrambi i casi

So che questo è particolarmente vecchio, ma aggiungerei una risposta che credo riguardi le informazioni mancanti dalla risposta con il voto più alto che potrebbero essere molto utili per chiunque lo trovi:

Per ciascuno dei seguenti metodi collegarli con un conteggio se è necessario accettare qualsiasi input. (Supponendo che stiamo usando definizioni vocali di numeri interi anziché 0-255, ecc.)

x.isdigit() funziona bene per verificare se x è un numero intero.

x.replace('-','').isdigit() funziona bene per verificare se x è negativo. (Controlla - in prima posizione)

x.replace('.','').isdigit() funziona bene per verificare se x è un decimale.

x.replace(':','').isdigit() funziona bene per verificare se x è un rapporto.

x.replace('/','',1).isdigit() funziona bene per verificare se x è una frazione.

Eseguire il cast su float e catturare ValueError è probabilmente il modo più veloce, poiché float () è specificamente pensato proprio per questo. Qualsiasi altra cosa che richieda l'analisi delle stringhe (regex, ecc.) Sarà probabilmente più lenta a causa del fatto che non è sintonizzata per questa operazione. I miei $ 0,02.

Puoi usare le stringhe Unicode, hanno un metodo per fare esattamente quello che vuoi:

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

o

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

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

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

Questa risposta fornisce una guida passo-passo con funzione con esempi per trovare la stringa:

  • Numero intero positivo
  • Positivo / negativo - intero / float
  • Come scartare " NaN " (non un numero) stringhe durante il controllo del numero?

Controlla se la stringa è positiva intera

Puoi utilizzare str.isdigit() per verificare se la stringa specificata è positiva intera.

Risultati del campione:

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

Controlla la stringa come positivo / negativo - intero / float

False restituisce float se la stringa è un numero negativo o un numero float. Ad esempio:

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

Se vuoi controllare anche gli negativi interi e True , quindi puoi scrivere una funzione personalizzata per verificarla come:

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

Esempio di esecuzione:

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

Elimina " NaN " (non un numero) stringhe durante il controllo del numero

Le funzioni sopra riportate restituiranno math.isnan() per il " NAN " (Non un numero) stringa perché per Python è un float valido che rappresenta non è un numero. Ad esempio:

>>> is_number('NaN')
True

Per verificare se il numero è " NaN " è possibile utilizzare == come:

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

>>> math.isnan(nan_num)
True

O se non vuoi importare libreria aggiuntiva per verificarlo, puoi semplicemente controllarlo confrontandolo con se stesso usando nan. Python restituisce is_number quando "NaN" il float viene confrontato con se stesso. Ad esempio:

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

Quindi, sopra la funzione <=> può essere aggiornata per restituire <=> per <=> come:

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

Esempio di esecuzione:

>>> 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: ogni operazione per ciascun controllo a seconda del tipo di numero comporta un sovraccarico aggiuntivo. Scegli la versione della funzione <=> adatta alle tue esigenze.

Volevo vedere quale metodo è il più veloce. Nel complesso, i risultati migliori e più coerenti sono stati forniti dalla funzione check_replace. I risultati più veloci sono stati forniti dalla funzione check_exception, ma solo se non è stata generata alcuna eccezione, il che significa che il suo codice è il più efficiente, ma il sovraccarico di generare un'eccezione è piuttosto grande.

Si noti che la verifica della riuscita del cast è l'unico metodo accurato, ad esempio, funziona con <=> ma le altre due funzioni di test restituiranno False per un float valido:

huge_number = float('1e+100')

Ecco il codice di riferimento:

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

Ecco i risultati con Python 2.7.10 su un MacBook Pro 13 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

Ecco i risultati con Python 3.6.5 su un MacBook Pro 13 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

Ecco i risultati con PyPy 2.7.13 su un MacBook Pro 13 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

Quindi, per mettere tutto insieme, controllando Nan, infinito e numeri complessi (sembrerebbe che siano specificati con j, non io, cioè 1 + 2j) si traduce in:

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

Ho fatto un test di velocità. Diciamo che se la stringa è probabile essere un numero, la strategia prova / tranne è la più veloce possibile. Se la stringa è non probabile a essere un numero e sei interessato a Controllo intero , vale la pena fare qualche test (isdigit più intestazione '-'). Se sei interessato a controllare il numero float, devi usare il codice prova / tranne senza escape.

Avevo bisogno di determinare se una stringa veniva lanciata in tipi base (float, int, str, bool). Dopo aver trovato nulla su Internet ho creato questo:

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)

Esempio

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       

Puoi acquisire il tipo e usarlo

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

L'input può essere il seguente:

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


1-input generale:

L'input di questa funzione può essere tutto!

Verifica se la variabile specificata è numerica. Le stringhe numeriche sono costituite da segno opzionale, qualsiasi numero di cifre, parte decimale opzionale e parte esponenziale opzionale. Pertanto + 0123.45e6 è un valore numerico valido. La notazione esadecimale (ad es. 0xf4c3b00c) e binaria (ad es. 0b10100111001) non è consentita.

is_numeric funzione

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

Test:

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

is_float funzione

Verifica se la variabile specificata è float. le stringhe float sono costituite da segno opzionale, qualsiasi numero di cifre, ...

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

Test:

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

che cos'è ast ?


2- Se sei sicuro che il contenuto della variabile sia Stringa :

usa il metodo 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 input numerici:

rileva valore int:

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

rileva float:

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

RyanN suggerisce

  

Se si desidera restituire False per NaN e Inf, cambiare la riga in x = float (s); return (x == x) e (x - 1! = x). Questo dovrebbe restituire True per tutti i float tranne Inf e NaN

Ma questo non funziona del tutto, perché per float sufficientemente grandi, x-1 == x restituisce true. Ad esempio, 2.0**54 - 1 == 2.0**54

Penso che la tua soluzione vada bene.

Detto questo, c'è molto odio regexp verso queste risposte che ritengo ingiustificato, le regexps possono essere ragionevolmente pulite, corrette e veloci. Dipende davvero da cosa stai cercando di fare. La domanda originale era: come & Quot; controllare se una stringa può essere rappresentata come un numero (float) & Quot; (secondo il tuo titolo). Presumibilmente vorrai usare il valore numerico / float dopo aver verificato che sia valido, nel qual caso il tuo tentativo / tranne ha molto senso. Ma se, per qualche motivo, vuoi solo confermare che una stringa è un numero , allora anche una regex funziona bene, ma è difficile ottenere la correzione. Penso che la maggior parte delle risposte regex finora, ad esempio, non analizzino correttamente le stringhe senza una parte intera (come & Quot; .7 & Quot;) che è un float per quanto riguarda python. E questo è leggermente complicato da verificare in una singola regex in cui non è richiesta la parte frazionaria. Ho incluso due regex per dimostrarlo.

Fa sorgere l'interessante domanda su cosa sia un " numero " è. Includete & Quot; inf & Quot; quale è valido come float in python? Oppure includi numeri che sono & Quot; numeri & Quot; ma forse non può essere rappresentato in Python (come numeri più grandi del float max).

Ci sono anche ambiguità nel modo in cui analizzi i numeri. Ad esempio, che dire di & Quot; - 20 & Quot ;? È questo un & Quot; numero & Quot ;? È un modo legale per rappresentare & Quot; 20 & Quot ;? Python ti permetterà di fare & Quot; var = --20 & Quot; e impostarlo su 20 (anche se in realtà questo è perché lo tratta come un'espressione), ma float (" - 20 ") non funziona.

Comunque, senza ulteriori informazioni, ecco una regex che credo copre tutti gli ints e float mentre Python li analizza .

# 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

Alcuni valori di prova di esempio:

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

Ho anche usato la funzione che hai citato, ma presto noto che le stringhe come " Nan " ;, " Inf " e la sua variazione è considerata come numero. Quindi ti propongo una versione migliorata della tua funzione, che restituirà false su quel tipo di input e non fallirà & Quot; 1e3 & Quot; varianti:

def is_float(text):
    try:
        float(text)
        # check for nan/infinity etc.
        if text.isalpha():
            return False
        return True
    except ValueError:
        return False
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

Questo codice gestisce esponenti, float e numeri interi, senza usare regex.

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

Ecco il mio modo semplice di farlo. Diciamo che sto attraversando alcune stringhe e voglio aggiungerle a un array se si rivelano numeri.

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

Sostituisci myvar.apppend con qualsiasi operazione tu voglia fare con la stringa se risulta essere un numero. L'idea è di provare a utilizzare un'operazione float () e utilizzare l'errore restituito per determinare se la stringa è o meno un numero.

Puoi generalizzare la tecnica dell'eccezione in modo utile restituendo valori più utili di Vero e Falso. Ad esempio questa funzione mette le virgolette attorno alle stringhe ma lascia numeri da soli. Il che è proprio quello di cui avevo bisogno per un filtro rapido e sporco per creare alcune definizioni variabili per 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:]), ')'

Stavo lavorando a un problema che mi ha portato a questo thread, vale a dire come convertire una raccolta di dati in stringhe e numeri nel modo più intuitivo. Dopo aver letto il codice originale ho capito che ciò di cui avevo bisogno era diverso in due modi:

1 - Volevo un risultato intero se la stringa rappresentava un intero

2 - Volevo che un risultato di un numero o una stringa rimanesse in una struttura di dati

quindi ho adattato il codice originale per produrre questa derivata:

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

Prova questo.

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

Funzione di aiuto dell'utente:

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

quindi

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

usare come segue gestisce tutti i casi: -

import re
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3') 
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '.3')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3sd')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3')
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top