Pregunta

¿Cuál es la mejor manera de comprobar si una cadena puede ser representado como un número en Python?

La función actualmente tengo ahora mismo es:

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

Que, no sólo es feo y lento, parece torpe.Sin embargo no he encontrado un método mejor porque al llamar float en la función main es aún peor.

¿Fue útil?

Solución

  

Que, no solo es feo y lento

Yo disputaría ambos.

Una expresión regular u otro método de análisis de cadenas sería más feo y lento.

No estoy seguro de que algo pueda ser más rápido que lo anterior. Llama a la función y vuelve. Try / Catch no introduce demasiados gastos generales porque la excepción más común se detecta sin una búsqueda exhaustiva 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 puede analizar ningún número válido.

C (como ejemplo) piratea esto de varias maneras. Python lo presenta de manera clara y explícita.

Creo que tu código para hacer esto es perfecto.

Otros consejos

En caso de que esté buscando enteros de análisis (positivo, sin signo) en lugar de flotantes, puede usar isdigit() función para objetos de cadena.

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

Métodos de cadena - <=>: Python2 , Python3

También hay algo en las cadenas Unicode, con lo que no estoy demasiado familiarizado Unicode - Es decimal / decimal

TL; DR La mejor solución es s.replace('.','',1).isdigit()

Hice algunos puntos de referencia 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, el método try-except es el único enfoque que maneja las anotaciones 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__)

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

Notación científica " 1.000000e + 50 " no es compatible con:
- is_number_regex
- is_number_repl_isdigit
Notación científica & Quot; 1e50 & Quot; 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()

 ingrese la descripci&oacute;n de la imagen aqu&iacute;

Hay una excepción que puede 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 en su representación de un número que no es un número (hablemos de problemas de identidad):

>>> float('NaN')
nan

De lo contrario, debería agradecerle el código que ahora uso ampliamente. :)

G.

¿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

editar: acabo de ver otro comentario ... Se puede agregar un .replace(badstuff,'',maxnum_badstuff) para otros casos. si está pasando sal y no condimentos arbitrarios (ref: xkcd # 974 ) esto funcionará bien: P

Actualizado después de que Alfe señaló que no es necesario verificar el flotador 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 dicho: es posible que también necesite verificar números complejos (p. ej., 1 + 2i), que no pueden representarse mediante un flotante:

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
  

Lo cual, no solo es feo y lento, parece torpe.

Puede llevar un tiempo acostumbrarse, pero esta es la forma pitónica de hacerlo. Como ya se señaló, las alternativas son peores. Pero hay otra ventaja de hacer las cosas de esta manera: el polimorfismo.

La idea central detrás de la escritura de patos es que & "; si camina y habla como un pato, entonces es un pato. &"; ¿Qué sucede si decide que necesita subclasificar cadenas 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? Puede hacer estas cosas sin tener que cambiar el código anterior.

Otros idiomas resuelven estos problemas mediante el uso de interfaces. Guardaré el análisis de qué solución es mejor para otro hilo. El punto, sin embargo, es que Python está decididamente del lado de la ecuación, y probablemente tendrá que acostumbrarse a una sintaxis como esta si planea hacer mucha programación en Python (pero eso no significa tiene que gustarle, por supuesto).

Otra cosa que quizás desee tener en cuenta: Python es bastante rápido en lanzar y capturar excepciones en comparación con muchos otros lenguajes (30 veces más rápido que .Net, por ejemplo). Diablos, el lenguaje en sí mismo incluso arroja excepciones para comunicar condiciones de programa normales y no excepcionales (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.

Para int use esto:

>>> "1221323".isdigit()
True

Pero para float necesitamos algunos trucos ;-). Cada número flotante 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 simplemente agregue lstrip():

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

Y ahora tenemos una forma universal:

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

Just 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 pregunta por qué cambié la excepción a 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 'Falso' booleano porque todavía es un tipo de valor. Ninguno es mejor porque indica falla. Por supuesto, si desea algo diferente, puede cambiar el parámetro de falla a lo que desee.

Para extender float para incluir 'parse ()' y 'try_parse ()', necesitará hacer un parche en la clase 'float' para agregar estos métodos.

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

Nota al margen: Personalmente prefiero llamarlo Monkey Punching porque parece que estoy abusando del idioma 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 le dijo a la Santa Sede Sharpisus, & "Todo lo que puedas hacer lo puedo hacer mejor; Puedo hacer cualquier cosa mejor que tú. & Quot;

Para cadenas de no números, try: except: en realidad es más lento que las expresiones regulares. Para cadenas de números válidos, regex es más lento. Entonces, el método apropiado depende de su entrada.

Si descubre que está en una situación de rendimiento, puede usar un nuevo módulo de terceros llamado fastnumbers que proporciona una función llamada isfloat . Divulgació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

  • fastnumbers fue rápido para la entrada numérica pero muy lento para una entrada no válida
  • regex es muy eficiente cuando la entrada no es válida
  • <=> gana en ambos casos

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 recuento si necesita que se acepte alguna entrada. (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. (Verificar - en la 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 relación.

x.replace('/','',1).isdigit() funciona bien para verificar si x es una fracción.

Lanzar a flotante y capturar ValueError es probablemente la forma más rápida, ya que float () está específicamente diseñado para eso. Cualquier otra cosa que requiera el análisis de cadenas (expresiones regulares, etc.) probablemente será más lenta debido al hecho de que no está ajustada para esta operación. Mis $ 0.02.

Puede usar cadenas Unicode, tienen un método para hacer exactamente lo que quiere:

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

Esta respuesta proporciona una guía paso a paso que tiene una función con ejemplos para encontrar la cadena es:

  • Entero positivo
  • Positivo / negativo - entero / flotante
  • Cómo descartar " NaN " (no un número) cadenas al verificar el número?

Compruebe si la cadena es positiva entera

Puede usar str.isdigit() para verificar si la cadena dada es un entero positivo .

Resultados de muestra:

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

Verifique la cadena como positiva / negativa - entero / flotante

False devuelve float 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 desea también verifique los enteros negativos y True , luego 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 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

Descartar " NaN " (no un número) cadenas al verificar el número

Las funciones anteriores devolverán math.isnan() para " NAN " (No es un número) cadena porque para Python es flotante válido que lo representa no es un número. Por ejemplo:

>>> is_number('NaN')
True

Para verificar si el número es " NaN " ;, puede usar == como:

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

>>> math.isnan(nan_num)
True

O si no desea importar una biblioteca adicional para verificar esto, entonces simplemente puede verificarlo comparándolo con nan. Python devuelve is_number cuando "NaN" flotante se compara con sí mismo. Por ejemplo:

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

Por lo tanto, la función anterior <=> se puede actualizar para devolver <=> para <=> 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 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

PD: cada operación para cada cheque, dependiendo del tipo de número, viene con una sobrecarga adicional. Elija la versión de la función <=> que se ajuste a sus necesidades.

Quería ver qué método es el más rápido. En general, los resultados mejores y más consistentes fueron dados por la función check_replace. La función check_exception proporciona los resultados más rápidos, pero solo si no se activó ninguna excepción, 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 una conversión exitosa es el único método que es preciso, por ejemplo, esto funciona con <=> pero las otras dos funciones de prueba devolverán False para un flotante 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))

Estos son los resultados con Python 2.7.10 en una 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 una 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 una 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

Entonces, para poner todo junto, verificando Nan, infinito y números complejos (parece que están especificados con j, no i, es decir, 1 + 2j) resulta en:

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

Hice una prueba de velocidad.Digamos que si la cadena es probablemente para ser un número de la try/except la estrategia es la forma más rápida posible.Si la cadena es no es probable para ser un número y usted está interesado en Entero el cheque, worths para hacer algunas pruebas (isdigit plus título '-').Si usted está interesado en comprobar float número, usted tiene que utilizar el try/except código whitout escapar.

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       

Puede capturar el tipo y usarlo

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

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 consisten en signos opcionales, 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. La notación hexadecimal (por ejemplo, 0xf4c3b00c) y binaria (por ejemplo, 0b10100111001) no está permitida.

is_numeric función

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

prueba:

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

is_float función

Encuentra si la variable dada es flotante. las cadenas flotantes consisten en signos opcionales, 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

¿Qué es ast ?


2- Si está seguro de que el contenido variable es Cadena :

use str.isdigit () método

>>> 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 de 3 números:

detectar valor int:

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

detectar flotante:

>>> 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); return (x == x) y (x - 1! = x). Esto debería devolver True para todas las carrozas excepto Inf y NaN

Pero esto no funciona del todo, porque para flotadores suficientemente grandes, x-1 == x devuelve verdadero. Por ejemplo, 2.0**54 - 1 == 2.0**54

Creo que tu solución está bien.

Habiendo dicho eso, hay mucho odio regexp hacia estas respuestas que creo que no está justificado, las expresiones regulares pueden ser razonablemente limpias, correctas y rápidas. Realmente depende de lo que intentes hacer. La pregunta original era ¿cómo puede & "; Verificar si una cadena se puede representar como un número (flotante) &"; (según su título). Presumiblemente, querrá usar el valor numérico / flotante una vez que haya verificado que es válido, en cuyo caso su intento / excepción tiene mucho sentido. Pero si, por alguna razón, solo desea validar que una cadena es un número , entonces una expresión regular también funciona bien, pero es difícil de corregir. Creo que la mayoría de las respuestas de expresiones regulares hasta ahora, por ejemplo, no analizan correctamente las cadenas sin una parte entera (como & Quot; .7 & Quot;) que es flotante en lo que respecta a python. Y eso es un poco difícil de verificar en una sola expresión regular donde no se requiere la porción fraccional. He incluido dos expresiones regulares para mostrar esto.

Se plantea la interesante pregunta de qué " número " es. ¿Incluye & Quot; inf & Quot; que es válido como flotador en python? ¿O incluye números que son & Quot; números & Quot; pero tal vez no se pueda representar en python (como números que son más grandes que el máximo flotante).

También hay ambigüedades en cómo analiza los números. Por ejemplo, ¿qué pasa con & Quot; - 20 & Quot ;? ¿Es esto un & Quot; número & Quot ;? ¿Es esta una forma legal de representar & Quot; 20 & Quot ;? Python te permitirá hacer & Quot; var = --20 & Quot; y configúrelo en 20 (aunque en realidad esto se debe a que lo trata como una expresión), pero float (" - 20 ") no funciona.

De todos modos, sin más información, aquí hay una expresión regular que creo que cubre todas las entradas y flota a medida que Python las analiza .

# 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

Algunos valores de prueba de ejemplo:

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

También utilicé la función que mencionaste, pero pronto noté que las cadenas como " Nan " ;, " Inf " y su variación se considera como número. Por lo tanto, le propongo una versión mejorada de su función, que devolverá falso en ese tipo de entrada y no fallará & Quot; 1e3 & Quot; variantes:

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

Este código maneja los exponentes, flotantes y enteros, sin usar expresiones regulares.

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

Aquí está mi manera simple de hacerlo. Digamos que estoy recorriendo 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 desee hacer con la cadena si resulta ser un número. La idea es intentar usar una operación float () y usar el error devuelto para determinar si la cadena es o no un número.

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 alrededor de las cadenas pero deja solo los números. Que es justo lo que necesitaba para un filtro rápido y sucio para hacer algunas definiciones 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:]), ')'

Estaba trabajando en un problema que me llevó a este hilo, a saber, cómo convertir una colección de datos a 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 pegue en una estructura de datos

así que adapté el código original para producir esta derivada:

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

Prueba esto.

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

Función de ayuda de usuario:

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

luego

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

utilizar siguiente maneja 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')
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top