ylab color categoryorder python string type-conversion

color - Comprobando si una cadena se puede convertir para flotar en Python



plotly layout (11)

Método Python para verificar float:

def isfloat(value): try: float(value) return True except ValueError: return False

¡No te muerdan los duendes que se esconden en el bote! ¡HAGA LAS PRUEBAS UNITARIAS!

Lo que es, y no es una carroza puede sorprenderlo:

Command to parse Is it a float? Comment -------------------------------------- --------------- ------------ print(isfloat("")) False print(isfloat("1234567")) True print(isfloat("NaN")) True nan is also float print(isfloat("NaNananana BATMAN")) False print(isfloat("123.456")) True print(isfloat("123.E4")) True print(isfloat(".1")) True print(isfloat("1,234")) False print(isfloat("NULL")) False case insensitive print(isfloat(",1")) False print(isfloat("123.EE4")) False print(isfloat("6.523537535629999e-07")) True print(isfloat("6e777777")) True This is same as Inf print(isfloat("-iNF")) True print(isfloat("1.797693e+308")) True print(isfloat("infinity")) True print(isfloat("infinity and BEYOND")) False print(isfloat("12.34.56")) False Two dots not allowed. print(isfloat("#56")) False print(isfloat("56%")) False print(isfloat("0E0")) True print(isfloat("x86E0")) False print(isfloat("86-5")) False print(isfloat("True")) False Boolean is not a float. print(isfloat(True)) True Boolean is a float print(isfloat("+1e1^5")) False print(isfloat("+1e1")) True print(isfloat("+1e1.3")) False print(isfloat("+1.3P1")) False print(isfloat("-+1")) False print(isfloat("(1)")) False brackets not interpreted

Tengo un código de Python que se ejecuta a través de una lista de cadenas y las convierte en números enteros o en coma flotante si es posible. Hacer esto para enteros es bastante fácil

if element.isdigit(): newelement = int(element)

Los números de coma flotante son más difíciles. En este momento estoy usando la partition(''.'') Para dividir la cadena y verificar que uno o ambos lados sean dígitos.

partition = element.partition(''.'') if (partition[0].isdigit() and partition[1] == ''.'' and partition[2].isdigit()) or (partition[0] == '''' and partition[1] == ''.'' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1] == ''.'' and partition[2] == ''''): newelement = float(element)

Esto funciona, pero obviamente la declaración if para eso es un poco oso. La otra solución que consideré es simplemente ajustar la conversión en un bloque try / catch y ver si tiene éxito, como se describe en esta pregunta .

¿Alguien tiene alguna otra idea? ¿Opiniones sobre los méritos relativos de la partición y los enfoques try / catch?


Esta expresión regular comprobará los números científicos de punto flotante:

^[-+]?(?:/b[0-9]+(?:/.[0-9]*)?|/.[0-9]+/b)(?:[eE][-+]?[0-9]+/b)?$

Sin embargo, creo que su mejor opción es usar el analizador en un intento.


Estaba buscando un código similar, pero parece que usar try / excepts es la mejor manera. Aquí está el código que estoy usando. Incluye una función de reintento si la entrada no es válida. Necesitaba verificar si la entrada era mayor que 0 y si es así convertirlo a un flotador.

def cleanInput(question,retry=False): inputValue = input("/n/nOnly positive numbers can be entered, please re-enter the value./n/n{}".format(question)) if retry else input(question) try: if float(inputValue) <= 0 : raise ValueError() else : return(float(inputValue)) except ValueError : return(cleanInput(question,retry=True)) willbefloat = cleanInput("Give me the number: ")


Si le preocupa el rendimiento (y no estoy sugiriendo que deba hacerlo), el enfoque basado en la prueba es el claro ganador (en comparación con su enfoque basado en particiones o el enfoque de expresiones regulares), siempre y cuando no espere mucho cadenas inválidas, en cuyo caso es potencialmente más lento (presumiblemente debido al costo del manejo de excepciones).

De nuevo, no estoy sugiriendo que se preocupe por el rendimiento, solo dándole los datos en caso de que esté haciendo esto 10 mil millones de veces por segundo, o algo así. Además, el código basado en particiones no maneja al menos una cadena válida.

$ ./floatstr.py F.. partition sad: 3.1102449894 partition happy: 2.09208488464 .. re sad: 7.76906108856 re happy: 7.09421992302 .. try sad: 12.1525540352 try happy: 1.44165301323 . ====================================================================== FAIL: test_partition (__main__.ConvertTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "./floatstr.py", line 48, in test_partition self.failUnless(is_float_partition("20e2")) AssertionError ---------------------------------------------------------------------- Ran 8 tests in 33.670s FAILED (failures=1)

Aquí está el código (Python 2.6, expresión regular tomada de la answer de John Gietzen):

def is_float_try(str): try: float(str) return True except ValueError: return False import re _float_regexp = re.compile(r"^[-+]?(?:/b[0-9]+(?:/.[0-9]*)?|/.[0-9]+/b)(?:[eE][-+]?[0-9]+/b)?$") def is_float_re(str): return re.match(_float_regexp, str) def is_float_partition(element): partition=element.partition(''.'') if (partition[0].isdigit() and partition[1]==''.'' and partition[2].isdigit()) or (partition[0]=='''' and partition[1]==''.'' and pa/ rtition[2].isdigit()) or (partition[0].isdigit() and partition[1]==''.'' and partition[2]==''''): return True if __name__ == ''__main__'': import unittest import timeit class ConvertTests(unittest.TestCase): def test_re(self): self.failUnless(is_float_re("20e2")) def test_try(self): self.failUnless(is_float_try("20e2")) def test_re_perf(self): print print ''re sad:'', timeit.Timer(''floatstr.is_float_re("12.2x")'', "import floatstr").timeit() print ''re happy:'', timeit.Timer(''floatstr.is_float_re("12.2")'', "import floatstr").timeit() def test_try_perf(self): print print ''try sad:'', timeit.Timer(''floatstr.is_float_try("12.2x")'', "import floatstr").timeit() print ''try happy:'', timeit.Timer(''floatstr.is_float_try("12.2")'', "import floatstr").timeit() def test_partition_perf(self): print print ''partition sad:'', timeit.Timer(''floatstr.is_float_partition("12.2x")'', "import floatstr").timeit() print ''partition happy:'', timeit.Timer(''floatstr.is_float_partition("12.2")'', "import floatstr").timeit() def test_partition(self): self.failUnless(is_float_partition("20e2")) def test_partition2(self): self.failUnless(is_float_partition(".2")) def test_partition3(self): self.failIf(is_float_partition("1234x.2")) unittest.main()


Si no necesita preocuparse por las expresiones científicas o de otro tipo de números, solo trabaja con cadenas que pueden ser números con o sin período:

Función

def is_float(s): result = False if s.count(".") == 1: if s.replace(".", "").isdigit(): result = True return result

Versión Lambda

is_float = lambda x: x.replace(''.'','''',1).isdigit() and "." in x

Ejemplo

if is_float(some_string): some_string = float(some_string) elif some_string.isdigit(): some_string = int(some_string) else: print "Does not convert to int or float."

De esta forma, no está convirtiendo accidentalmente lo que debería ser un int, en un float.


Solo por variedad aquí hay otro método para hacerlo.

>>> all([i.isnumeric() for i in ''1.2''.split(''.'',1)]) True >>> all([i.isnumeric() for i in ''2''.split(''.'',1)]) True >>> all([i.isnumeric() for i in ''2.f''.split(''.'',1)]) False

Editar: estoy seguro de que no se mantendrá hasta todos los casos de flotación, especialmente cuando hay un exponente. Para resolver eso se ve así. Esto devolverá True only val is a float y False for int pero es probablemente menos eficiente que regex.

>>> def isfloat(val): ... return all([ [any([i.isnumeric(), i in [''.'',''e'']]) for i in val], len(val.split(''.'')) == 2] ) ... >>> isfloat(''1'') False >>> isfloat(''1.2'') True >>> isfloat(''1.2e3'') True >>> isfloat(''12e3'') False


Usé la función ya mencionada, pero pronto noté que las cadenas como "Nan", "Inf" y su variación se consideran como números. Así que propongo una versión mejorada de la 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


Yo solo usaría ...

try: float(element) except ValueError: print "Not a float"

..es simple, y funciona

Otra opción sería una expresión regular:

import re if re.match("^/d+?/./d+?$", element) is None: print "Not float"


str (strval) .isdigit () parece ser simple. Maneja los valores almacenados como una cadena o int o float


TL; DR :

  • Si su entrada es principalmente cadenas que se pueden convertir en flotantes, el método try: except: es el mejor método nativo de Python.
  • Si su entrada es principalmente cadenas que no se pueden convertir en flotantes, las expresiones regulares o el método de partición serán mejores.
  • Si tiene 1) dudas sobre su información o si necesita más velocidad y 2) no tiene inconveniente y puede instalar una extensión C de terceros, fastnumbers funciona muy bien.

Hay otro método disponible a través de un módulo de terceros denominado fastnumbers (divulgación, soy el autor); proporciona una función llamada isfloat . Tomé el ejemplo de unittest descrito por Jacob Gabrielson en esta respuesta , pero agregué el método fastnumbers.isfloat . También debo señalar que el ejemplo de Jacob no hizo justicia a la opción de expresión regular porque la mayoría de las veces en ese ejemplo se gastó en búsquedas globales debido al operador punto ... He modificado esa función para ofrecer una comparación más justa para try: except: .

def is_float_try(str): try: float(str) return True except ValueError: return False import re _float_regexp = re.compile(r"^[-+]?(?:/b[0-9]+(?:/.[0-9]*)?|/.[0-9]+/b)(?:[eE][-+]?[0-9]+/b)?$").match def is_float_re(str): return True if _float_regexp(str) else False def is_float_partition(element): partition=element.partition(''.'') if (partition[0].isdigit() and partition[1]==''.'' and partition[2].isdigit()) or (partition[0]=='''' and partition[1]==''.'' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1]==''.'' and partition[2]==''''): return True else: return False from fastnumbers import isfloat if __name__ == ''__main__'': import unittest import timeit class ConvertTests(unittest.TestCase): def test_re_perf(self): print print ''re sad:'', timeit.Timer(''ttest.is_float_re("12.2x")'', "import ttest").timeit() print ''re happy:'', timeit.Timer(''ttest.is_float_re("12.2")'', "import ttest").timeit() def test_try_perf(self): print print ''try sad:'', timeit.Timer(''ttest.is_float_try("12.2x")'', "import ttest").timeit() print ''try happy:'', timeit.Timer(''ttest.is_float_try("12.2")'', "import ttest").timeit() def test_fn_perf(self): print print ''fn sad:'', timeit.Timer(''ttest.isfloat("12.2x")'', "import ttest").timeit() print ''fn happy:'', timeit.Timer(''ttest.isfloat("12.2")'', "import ttest").timeit() def test_part_perf(self): print print ''part sad:'', timeit.Timer(''ttest.is_float_partition("12.2x")'', "import ttest").timeit() print ''part happy:'', timeit.Timer(''ttest.is_float_partition("12.2")'', "import ttest").timeit() unittest.main()

En mi máquina, la salida es:

fn sad: 0.220988988876 fn happy: 0.212214946747 . part sad: 1.2219619751 part happy: 0.754667043686 . re sad: 1.50515985489 re happy: 1.01107215881 . try sad: 2.40243887901 try happy: 0.425730228424 . ---------------------------------------------------------------------- Ran 4 tests in 7.761s OK

Como puede ver, Regex en realidad no es tan malo como originalmente parecía, y si tiene una necesidad real de velocidad, el método de fastnumbers es bastante bueno.


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

que volverá true solo si hay uno o no ''.'' en la cadena de dígitos.

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

devolverá false

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

devolverá false