Come posso verificare se una stringa è un numero (float)?
-
20-08-2019 - |
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.
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()
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
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')