una - validar numero entero python
¿Cómo verifico si una cadena es un número(float)? (30)
Lo cual, no solo es feo y lento, parece torpe.
Puede tomar algún tiempo acostumbrarse, pero esta es la forma pitónica de hacerlo. Como ya se ha señalado, las alternativas son peores. Pero hay otra ventaja de hacer las cosas de esta manera: el polimorfismo.
La idea central detrás de la tipificación del pato es que "si camina y habla como un pato, entonces es un pato". ¿Qué sucede si decide que necesita crear una subclase de cadena para poder cambiar la forma en que determina si algo se puede convertir en un flotador? O ¿qué pasa si decides probar algún otro objeto por completo? Puedes hacer estas cosas sin tener que cambiar el código anterior.
Otros lenguajes resuelven estos problemas usando interfaces. Guardaré el análisis de qué solución es mejor para otro hilo. Sin embargo, el punto es que python está decididamente en el lado de la ecuación al escribir pato, y probablemente tendrás que acostumbrarte a una sintaxis como esta si planeas hacer mucha programación en Python (pero eso no significa tienes que gustarte por supuesto).
Otra cosa que debería tener en cuenta: Python es bastante rápido en lanzar y capturar excepciones en comparación con muchos otros idiomas (30 veces más rápido que .Net, por ejemplo). Diablos, el lenguaje en sí mismo incluso genera excepciones para comunicar condiciones normales y no excepcionales del programa (cada vez que usa un bucle for). Por lo tanto, no me preocuparía demasiado por los aspectos de rendimiento de este código hasta que note un problema importante.
¿Cuál es la mejor manera de verificar si una cadena se puede representar como un número en Python?
La función que tengo actualmente en este momento es:
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
Lo cual, no solo es feo y lento, parece torpe. Sin embargo, no he encontrado un método mejor porque llamar a float
en la función principal es aún peor.
Lo cual, no solo es feo y lento.
Yo disputaría ambos.
Una expresión regular u otro análisis de cadena sería más feo y lento.
No estoy seguro de que nada sea más rápido que lo anterior. Llama a la función y vuelve. Try / Catch no presenta mucha sobrecarga porque la excepción más común se detecta sin una búsqueda extensa de marcos de pila.
El problema es que cualquier función de conversión numérica tiene dos tipos de resultados
- Un número, si el número es válido
- Un código de estado (por ejemplo, a través de errno) o una excepción para mostrar que no se pudo analizar un número válido.
C (como ejemplo) hacks alrededor de esto de varias maneras. Python lo expone de forma clara y explícita.
Creo que tu código para hacer esto es perfecto.
Solo mimic c #
En C # hay dos funciones diferentes que manejan el análisis de valores escalares:
- Float.Parse ()
- Float.TryParse ()
float.parse ():
def parse(string):
try:
return float(string)
except Exception:
throw TypeError
Nota: Si se está preguntando por qué cambié la excepción a un TypeError, aquí está la documentación .
float.try_parse ():
def try_parse(string, fail=None):
try:
return float(string)
except Exception:
return fail;
Nota: no desea devolver el booleano ''False'' porque sigue siendo un tipo de valor. Ninguna es mejor porque indica fracaso. Por supuesto, si quieres algo diferente, puedes cambiar el parámetro de falla a lo que quieras.
Para extender float a fin de incluir el ''parse ()'' y ''try_parse ()'' necesitarás hacer un monkeypatch en la clase ''float'' para agregar estos métodos.
Si quieres respetar las funciones preexistentes, el código debería ser algo como:
def monkey_patch():
if(!hasattr(float, ''parse'')):
float.parse = parse
if(!hasattr(float, ''try_parse'')):
float.try_parse = try_parse
SideNote: Personalmente prefiero llamarlo Monkey Punching porque se siente como si estuviera abusando del lenguaje cuando hago esto, pero YMMV.
Uso:
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
Y el gran Sabio Pythonas dijo a la Santa Sede Sharpisus: "Todo lo que pueda hacer lo puedo hacer mejor; puedo hacer cualquier cosa mejor que usted".
Actualizado después de que Alfe señaló que no es necesario verificar la flotación por separado, ya que el complejo maneja ambos:
def is_number(s):
try:
complex(s) # for int, long, float and complex
except ValueError:
return False
return True
Anteriormente dijo: Es un caso raro que también necesite verificar los números complejos (por ejemplo, 1 + 2i), que no pueden ser representados por un flotador:
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
Casting to float y la captura de ValueError es probablemente la forma más rápida, ya que float () está específicamente diseñado para eso. Cualquier otra cosa que requiera análisis de cadenas (expresiones regulares, etc.) será más lenta debido al hecho de que no está sintonizada para esta operación. Mis $ 0.02.
Digamos que tienes dígitos en la cadena. str = "100949" y le gustaría verificar si solo tiene números
if str.isdigit():
returns TRUE or FALSE
de lo contrario, su método funciona muy bien para encontrar la aparición de un dígito en una cadena.
En caso de que esté buscando enteros de análisis (positivos, sin signo) en lugar de flotantes, puede usar la función isdigit()
para objetos de cadena.
>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False
También hay algo en las cadenas Unicode, que no estoy muy familiarizado con Unicode. Es decimal / decimal
Entonces, para ponerlo todo junto, verificando Nan, el infinito y los números complejos (parece que están especificados con j, no i, es decir, 1 + 2j) da como resultado:
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
Esta respuesta proporciona una guía paso a paso que tiene una función con ejemplos para encontrar la cadena:
- Entero positivo
- Positivo / negativo - entero / flotador
- ¿Cómo descartar cadenas "NaN" (no un número) mientras se verifica el número?
Compruebe si la cadena es un entero positivo
Puede usar isdigit() para verificar si la cadena dada es un entero positivo .
Resultados de la muestra:
# For digit
>>> ''1''.isdigit()
True
>>> ''1''.isalpha()
False
Compruebe si la cadena es positiva / negativa - entero / flotante
str.isdigit()
devuelve False
si la cadena es un número negativo o un número flotante. Por ejemplo:
# returns `False` for float
>>> ''123.3''.isdigit()
False
# returns `False` for negative number
>>> ''-123''.isdigit()
False
Si también desea verificar los enteros negativos y float
, puede escribir una función personalizada para verificarlo como:
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
Ejecución de la muestra:
>>> 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
Deseche las cadenas "NaN" (no un número) mientras verifica el número
Las funciones anteriores devolverán True
para la cadena "NAN" (no un número) porque para Python es un valor flotante válido que representa que no es un número. Por ejemplo:
>>> is_number(''NaN'')
True
Para verificar si el número es "NaN", puede usar math.isnan()
como:
>>> import math
>>> nan_num = float(''nan'')
>>> math.isnan(nan_num)
True
O si no quiere importar una biblioteca adicional para verificar esto, entonces simplemente puede verificarlo comparándolo con él mismo utilizando ==
. Python devuelve False
cuando se compara nan
float consigo mismo. Por ejemplo:
# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False
Por lo tanto, la función anterior is_number
se puede actualizar para devolver False
para "NaN"
como:
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
Ejecución de la muestra:
>>> 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: Cada operación para cada verificación, según el tipo de número, conlleva una sobrecarga adicional. Elija la versión de la función is_number
que se ajuste a sus necesidades.
Hay una excepción que deberías tener en cuenta: la cadena ''NaN''
Si desea que is_number devuelva FALSE para ''NaN'', este código no funcionará ya que Python lo convierte a su representación de un número que no es un número (hable sobre los problemas de identidad):
>>> float(''NaN'')
nan
De lo contrario, debería agradecerle por el código que ahora uso ampliamente. :)
SOL.
Hice alguna prueba de velocidad. Digamos que si es probable que la cadena sea un número, la estrategia try / except es la más rápida posible. Si no es probable que la cadena sea un número y usted está interesado en la verificación de enteros , vale la pena hacer una prueba (es un dígito más el encabezado ''-''). Si está interesado en verificar el número flotante, tiene que usar el código try / except whitoutoutout.
Para int
use esto:
>>> "1221323".isdigit()
True
Pero para float
necesitamos algunos trucos ;-). Cada número de flotador tiene un punto ...
>>> "12.34".isdigit()
False
>>> "12.34".replace(''.'','''',1).isdigit()
True
>>> "12.3.4".replace(''.'','''',1).isdigit()
False
También para números negativos solo agrega lstrip()
:
>>> ''-12''.lstrip(''-'')
''12''
Y ahora conseguimos un camino universal:
>>> ''-12.34''.lstrip(''-'').replace(''.'','''',1).isdigit()
True
>>> ''.-234''.lstrip(''-'').replace(''.'','''',1).isdigit()
False
Para cadenas de no números, try: except:
realidad es más lento que las expresiones regulares. Para cadenas de números válidos, la expresión regular es más lenta. Por lo tanto, el método apropiado depende de su entrada.
Si descubre que está en un enlace de rendimiento, puede usar un nuevo módulo de terceros llamado fastnumbers que proporciona una función llamada isfloat . Revelación completa, soy el autor. He incluido sus resultados en los horarios a continuación.
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
Como puedes ver
-
try: except:
era rápido para la entrada numérica pero muy lento para una entrada no válida - La expresión regular es muy eficiente cuando la entrada no es válida
-
fastnumbers
gana en ambos casos
Prueba esto.
def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False
Puedes usar cadenas Unicode, tienen un método para hacer lo que quieras:
>>> s = u"345"
>>> s.isnumeric()
True
O:
>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True
Qué tal esto:
''3.14''.replace(''.'','''',1).isdigit()
que devolverá verdadero solo si hay uno o no ''.'' en la cadena de dígitos.
''3.14.5''.replace(''.'','''',1).isdigit()
devolverá falso
edit: acabo de ver otro comentario ... agregando un .replace(badstuff,'''',maxnum_badstuff)
para otros casos se puede hacer. Si está pasando sal y no condimentos arbitrarios (ref: xkcd#974 ) esto funcionará bien: P
Quería ver qué método es el más rápido. En general, la función check_replace
proporcionó los mejores y más consistentes resultados. Los resultados más rápidos fueron dados por la función check_exception
, pero solo si no hubo una excepción check_exception
, lo que significa que su código es el más eficiente, pero la sobrecarga de lanzar una excepción es bastante grande.
Tenga en cuenta que la comprobación de un lanzamiento exitoso es el único método que es preciso, por ejemplo, esto funciona con check_exception
pero las otras dos funciones de prueba devolverán False para un flotador válido:
huge_number = float(''1e+100'')
Aquí está el código de referencia:
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))
Aquí están los resultados con Python 2.7.10 en 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
Aquí están los resultados con Python 3.6.5 en 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
Aquí están los resultados con PyPy 2.7.13 en 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
Sé que esto es particularmente antiguo, pero agregaría una respuesta que creo que cubre la información que falta en la respuesta más votada que podría ser muy valiosa para cualquiera que encuentre esto:
Para cada uno de los siguientes métodos, conéctelos con un conteo si necesita alguna entrada para ser aceptado. (Suponiendo que estamos usando definiciones vocales de enteros en lugar de 0-255, etc.)
x.isdigit()
funciona bien para verificar si x es un número entero.
x.replace(''-'','''').isdigit()
funciona bien para verificar si x es negativo (check - in primera posición)
x.replace(''.'','''').isdigit()
funciona bien para verificar si x es un decimal.
x.replace('':'','''').isdigit()
funciona bien para verificar si x es una proporción.
x.replace(''/'','''',1).isdigit()
funciona bien para verificar si x es una fracción.
Tu código me parece bien.
Tal vez usted piensa que el código es "torpe" debido al uso de excepciones? Tenga en cuenta que los programadores de Python tienden a utilizar las excepciones generosamente cuando mejora la legibilidad del código, gracias a su baja penalización de rendimiento.
TL; DR La mejor solución es s.replace(''.'','''',1).isdigit()
Hice algunos benchmarks comparando los diferentes enfoques.
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()
Si la cadena no es un número, el bloque de excepción es bastante lento. Pero lo más importante es que el método try-except es el único enfoque que maneja las notaciones científicas correctamente.
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__)
La notación flotante ".1234" no es compatible con:
- 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__)
La notación científica "1.000000e + 50" no es compatible con:
- is_number_regex
- is_number_repl_isdigit
La notación científica "1e50" no es compatible con:
- is_number_regex
- is_number_repl_isdigit
EDITAR: Los resultados de referencia.
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)))
donde se probaron las siguientes funciones
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()
El uso siguiente se encarga de todos los casos: -
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'')
La entrada puede ser la siguiente:
a="50"
b=50
c=50.1
d="50.1"
1-Entrada general:
¡La entrada de esta función puede ser todo!
Encuentra si la variable dada es numérica. Las cadenas numéricas constan de signo opcional, cualquier número de dígitos, parte decimal opcional y parte exponencial opcional. Por lo tanto, + 0123.45e6 es un valor numérico válido. No se permite la notación hexadecimal (por ejemplo, 0xf4c3b00c) y binaria (por ejemplo, 0b10100111001).
función is_numérica
import ast
import number
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
prueba:
>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True
función is_float
Encuentra si la variable dada es float. las cadenas flotantes constan de un signo opcional, cualquier número de dígitos, ...
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
prueba:
>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True
lo que es ast ?
2- Si está seguro de que el contenido variable es String :
usar el método 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
Entrada 3-Numérica:
detectar valor int:
>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>>
detectar flotar
>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True
RyanN sugiere
Si desea devolver False para un NaN e Inf, cambie la línea a x = float (s); devuelve (x == x) y (x - 1! = x). Esto debería devolver True para todos los flotadores excepto Inf y NaN.
Pero esto no funciona del todo, porque para flotadores suficientemente grandes, x-1 == x
devuelve true. Por ejemplo,2.0**54 - 1 == 2.0**54
Aquí está mi manera simple de hacerlo. Digamos que estoy haciendo un bucle a través de algunas cadenas y quiero agregarlas a una matriz si resultan ser números.
try:
myvar.append( float(string_to_check) )
except:
continue
Reemplace myvar.apppend con cualquier operación que quiera hacer con la cadena si resulta ser un número. La idea es tratar de usar una operación float () y usar el error devuelto para determinar si la cadena es un número o no.
Estaba trabajando en un problema que me llevó a este hilo, a saber, cómo convertir una colección de datos en cadenas y números de la manera más intuitiva. Después de leer el código original, me di cuenta de que lo que necesitaba era diferente de dos maneras:
1 - Quería un resultado entero si la cadena representaba un entero
2 - Quería que un número o un resultado de cadena se adhiriera a una estructura de datos
Así que adapté el código original para producir este derivado:
def string_or_number(s):
try:
z = int(s)
return z
except ValueError:
try:
z = float(s)
return z
except ValueError:
return s
Necesitaba determinar si una cadena se convertía en tipos básicos (float, int, str, bool). Después de no encontrar nada en internet creé esto:
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)
Ejemplo
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
Puedes capturar el tipo y usarlo.
s = "6.0"
type_ = str_to_type(s) # float
f = type_(s)
Puede generalizar la técnica de excepción de una manera útil devolviendo valores más útiles que Verdadero y Falso. Por ejemplo, esta función pone comillas en cadenas, pero deja números solos. Que es justo lo que necesitaba para un filtro rápido y sucio para hacer algunas definiciones de variables para 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:]), '')''
Si quieres saber si la cadena completa se puede representar como un número, querrás usar una expresión regular (o quizás convertir el flotante de nuevo en una cadena y compararlo con la cadena de origen, pero supongo que no es muy rápido ).
También utilicé la función que mencionaste, pero pronto noté que las cadenas como "Nan", "Inf" y su variación se consideran números. Por lo tanto, le propongo una versión mejorada de su función, que devolverá falso en ese tipo de entrada y no fallará en las variantes "1e3":
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