Pergunta

O que é a melhor maneira possível verificar se uma string pode ser representado como um número em Python?

A função atualmente eu tenho agora é:

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

O que, não só é feio e lento, parece desajeitado. No entanto, eu não encontrei um método melhor, porque chamando float na função principal é ainda pior.

Foi útil?

Solução

O que, não só é feio e lento

Eu disputar ambos.

A regex ou outro método de análise corda seria mais feio e mais lento.

Eu não tenho certeza que muita coisa poderia ser mais rápido do que o anterior. Ele chama a função e retorna. Try / catch não introduz muita sobrecarga porque a exceção mais comum é pego sem uma extensa pesquisa de quadros de pilha.

A questão é que qualquer função de conversão numérica tem dois tipos de resultados

  • Um número, se o número é válido
  • Um código de estado (por exemplo, através de errno) ou excepção para mostrar que nenhum número válido pôde ser analisado.

C (como um exemplo) hacks em torno deste um número de maneiras. Python coloca-lo de forma clara e explicitamente.

Eu acho que o seu código para fazer isso é perfeito.

Outras dicas

No caso de você está procurando analisar inteiros (positivos, não assinado) em vez de carros alegóricos, você pode usar o isdigit() função str.isdigit para objetos string.

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

Métodos String - isdigit(): python2 , Python3

Há também algo sobre cadeias de caracteres Unicode, que eu não estou muito familiarizado com Unicode - É decimal / decimal

TL; DR A melhor solução é s.replace('.','',1).isdigit()

Eu fiz alguma benchmarks comparando as diferentes abordagens

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 a cadeia não é um número, o bloco exceção é bastante lento. Mas o mais importante, o try-excepto método é a única abordagem que lida com Notação Científica corretamente.

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

notação Float" 0,1234" não é suportado por:
- 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__)

A notação científica "1.000000e + 50" não é suportado por:
- is_number_regex
- is_number_repl_isdigit
notação científica "1e50" não é suportado por:
- is_number_regex
- is_number_repl_isdigit

EDIT: Os resultados do 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)))

em que as funções seguintes foram testados

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

 enter descrição da imagem aqui

Há uma exceção que você pode querer ter em conta: a string 'NaN'

Se você quiser is_number para FALSE troca de 'NaN' este código não funcionará como Python converte em sua representação de um número que não é um número (falar sobre questões de identidade):

>>> float('NaN')
nan

Caso contrário, eu deveria realmente agradecer o pedaço de código que eu agora usar extensivamente. :)

G.

e quanto a isso:

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

que irá retornar apenas verdadeiro se houver um ou nenhum '' na seqüência de dígitos.

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

retornará false

Edit: Só vi outro comentário ... adicionando um .replace(badstuff,'',maxnum_badstuff) para outros casos pode ser feito. se você estiver passando sal e não condimentos arbitrárias (ref: xkcd # 974 ) isso vai fazer muito bem: P

atualizado após Alfe apontou você não precisa verificar se há flutuador separadamente como alças complexas ambos:

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

    return True

Anteriormente disse: É alguns casos raros, você também pode precisar verificar se há números complexos (por exemplo, 1 + 2i), que não podem ser representados por um 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

O que, não só é feio e lento, parece desajeitado.

Pode levar algum tempo para se acostumar, mas esta é a maneira Python de fazê-lo. Como já foi referido, as alternativas são piores. Mas há uma outra vantagem de fazer as coisas desta maneira:. Polimorfismo

A idéia central por trás tipagem pato é que "se ele anda e fala como um pato, então é um pato." E se você decidir que você precisa para string subclasse de modo que você pode mudar a forma como você determinar se algo pode ser convertida em uma bóia? Ou que se você decidir testar algum outro objeto inteiramente? Você pode fazer essas coisas sem ter que mudar o código acima.

Outros idiomas resolver esses problemas usando interfaces. Vou guardar a análise de qual solução é melhor para outro segmento. A questão, porém, é que python é decididamente no lado do pato digitação da equação, e você provavelmente vai ter que se acostumar a sintaxe como esta, se você planeja fazer muita programação em Python (mas isso não significa você tem que gostar dele, claro).

Uma outra coisa que você pode querer tomar em consideração: Python é muito rápido em jogar e pegar exceções em comparação com um monte de outras línguas (30x mais rápido do que .Net por exemplo). Heck, a linguagem em si mesmo gera exceções para se comunicar não-excepcionais, as condições do programa normal (cada vez que você usar um loop). Assim, eu não me preocuparia muito com os aspectos de desempenho deste código até que você observe um problema significativo.

Para uso int isto:

>>> "1221323".isdigit()
True

Mas para float precisamos de alguns truques ;-). Cada número flutuador possui um ponto ...

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

Também para números negativos basta adicionar lstrip():

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

E agora temos uma maneira universal:

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

Apenas Mimic C #

Em C # há duas funções diferentes que pega análise de valores escalares:

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

float.parse ():

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

Nota: Se você está se perguntando por que eu mudei a exceção para um TypeError, aqui está a documentação .

float.try_parse ():

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

Nota: Você não quer retornar o booleano 'False' porque isso é ainda um tipo de valor. Nenhum é melhor porque indica falha. Claro, se você quiser algo diferente, você pode alterar o parâmetro não conseguem o que quiser.

Para estender flutuador incluir o 'parse ()' e 'try_parse ()' você precisa monkeypatch a classe 'float' para adicionar esses métodos.

Se você quer respeito funções pré-existentes o código deve ser algo como:

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

SideNote:. Eu, pessoalmente, prefiro chamá-lo Macaco Punching porque parece que estou abusando da linguagem quando eu faço isso, mas 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

E o grande sábio Pythonas disse à Santa Sé Sharpisus, "Qualquer coisa que você pode fazer Eu posso fazer melhor;. Não posso fazer nada melhor do que você"

Para cadeias de não-números, try: except: é realmente mais lento do que expressões regulares. Para seqüências de números válidos, regex é mais lento. Assim, o método adequado depende de sua entrada.

Se você achar que você está em um ligamento desempenho, você pode usar um novo módulo de terceiros chamado fastnumbers que fornece uma função chamada isfloat . A divulgação completa, eu sou o autor. Eu incluí seus resultados nos horários abaixo.


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 você pode ver

  • try: except: foi rápido para entrada numérica, mas muito lento para uma entrada inválida
  • regex é muito eficiente quando a entrada é inválido
  • vitórias fastnumbers em ambos os casos

Eu sei que isto é particularmente velho, mas eu gostaria de acrescentar uma resposta Acredito tampas a informação em falta a partir do mais votado resposta que poderia ser muito valioso para qualquer um que encontrar este:

Para cada um dos seguintes métodos conectá-los com uma contagem, se você precisar de qualquer entrada para ser aceite. (Supondo que estamos usando definições vocais de números inteiros, em vez de 0-255, etc.)

x.isdigit() funciona bem para verificar se x é um inteiro.

x.replace('-','').isdigit() . Funciona bem para verificar se x é um negativo (Confira - na primeira posição)

x.replace('.','').isdigit() funciona bem para verificar se x é um decimal.

x.replace(':','').isdigit() funciona bem para verificar se x é uma relação.

x.replace('/','',1).isdigit() funciona bem para verificar se x é uma fração.

A projeção para flutuar e captura ValueError é provavelmente a maneira mais rápida, uma vez float () é especificamente destinado para isso. Qualquer outra coisa que requer análise de cadeia (regex, etc) provavelmente será mais lento devido ao fato de que ele não está sintonizado para esta operação. Minha US $ 0,02.

Você pode usar cadeias de caracteres Unicode, eles têm um método para fazer exatamente o que você quer:

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

Ou:

>>> 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 resposta fornece guia passo a passo tendo função com exemplos para encontrar a string é:

  • Inteiro positivo
  • positivo / negativo - inteiro / float
  • Como descartar cordas "NaN" (não um número) durante a verificação de número?

Verifica se o texto é positivo inteira

Você pode usar str.isdigit() para verificar se determinada string é positivo inteiro.

Resultados da Amostra:

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

Verificar string como positivo / negativo - inteiro / float

str.isdigit() retornos False se a string é uma negativo número ou uma bóia número. Por exemplo:

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

Se você quiser rel também verificar os negativo inteiros e float , então você pode escrever uma função personalizada para verificar se há-lo 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

Executar Amostra:

>>> 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" (não um número) cordas durante a verificação de número

As funções acima retornará True para o "NAN" (não um número) corda porque para Python é flutuante válido representando não é um número. Por exemplo:

>>> is_number('NaN')
True

A fim de verificar se o número é "NaN", você pode usar math.isnan() como:

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

>>> math.isnan(nan_num)
True

Ou se você não quiser importar biblioteca adicional de verificar isso, então você pode simplesmente verificar se via comparando-a com a própria usando ==. Python retorna False quando nan flutuador é comparado com ele mesmo. Por exemplo:

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

Por isso, acima de is_number função pode ser atualizado para retornar 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

Executar Amostra:

>>> 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 operação para cada verificação, dependendo do tipo de número vem com sobrecarga adicional. Escolha a versão da função is_number que se adapta à sua exigência.

Eu queria ver qual método é mais rápido. Em geral, os melhores e mais consistentes resultados foram dadas pela função check_replace. Os resultados mais rápidos foram dadas pela função check_exception, mas apenas se não houve exceção disparado -. Significando seu código é o mais eficiente, mas a sobrecarga de lançar uma exceção é bastante grande

Por favor note que a verificação de um elenco bem sucedido é o único método que é preciso, por exemplo, isso funciona com check_exception mas as outras duas funções de teste retornará False para um flutuador válido:

huge_number = float('1e+100')

Aqui está o código de referência:

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

Aqui estão os resultados com Python 2.7.10 em um 2017 MacBook Pro 13:

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

Aqui estão os resultados com Python 3.6.5 em um 2017 MacBook Pro 13:

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

Aqui estão os resultados com PyPy 2.7.13 em um 2017 MacBook Pro 13:

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

Então, para colocá-lo todos juntos, a verificação de Nan, infinito e números complexos (parece que eles são especificados com j, não eu, ou seja, 1 + 2j) resulta em:

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

Eu fiz alguns testes de velocidade. Vamos dizer que se a cadeia é provável para ser um número do try / except estratégia é o mais rápido possible.If a corda é não é provável para ser um número e você está interessado em Integer cheque, valha a pena fazer algum teste (isdigit além título '-'). Se você estiver interessado em verificar o número de float, você tem que usar o try / except código whitout fuga.

I necessários para determinar se um elenco string em tipos básicos (float, int, str, bool). Depois de não encontrar qualquer coisa na internet que eu criei esta:

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)

Exemplo

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       

Você pode capturar o tipo e usá-lo

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

A entrada pode ser como se segue:

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


entrada 1-Geral:

A entrada desta função pode ser tudo!

Verifica se uma dada variável é numérico. cordas numéricos consistem de sinal opcional, qualquer número de dígitos, parte decimal opcional e parte exponencial opcional. Assim + 0123.45e6 é um valor numérico válido. Hexadecimal (por exemplo 0xf4c3b00c) e binário (por exemplo 0b10100111001) notação não é permitido.

is_numeric Função

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

teste:

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

is_float Função

Verifica se uma dada variável é float. cordas flutuador consistem de sinal opcional, qualquer 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

teste:

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

o que é ast ?


2 Se você estiver confiante de que o conteúdo variável é string :

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 numérica:

detectar valor int:

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

detectar float:

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

Ryann sugere

Se você quiser retornar False para um NaN e Inf, linha mudança x = float (s); return (x == x) e (x - 1 = x!). Isso deve retornar verdadeiro para todos os carros alegóricos, exceto Inf e NaN

Mas isso não funciona muito bem, porque para suficientemente grandes carros alegóricos, x-1 == x retorna verdadeiro. Por exemplo, 2.0**54 - 1 == 2.0**54

Eu acho que a solução está bem.

Dito isto, há um monte de ódio regexp para estas respostas que eu acho que não é justificada, regexps pode ser razoavelmente limpo e correto e rápido. Ela realmente depende do que você está tentando fazer. A pergunta original era como você pode "verificar se uma string pode ser representado como um número (float)" (de acordo com o seu título). Provavelmente, você iria querer usar o valor / float numérica Depois de ter verificado que é válido, caso em que o seu try / exceto faz muito sentido. Mas se, por algum motivo, você quer apenas para validar que um string é um número , em seguida, um regex também funciona bem, mas é difícil para obter correta. Eu acho que a maioria das respostas regex até agora, por exemplo, não fazer cordas corretamente de análise sem uma parte inteira (como" 0,7" ), que é um float, tanto quanto python está em causa. E isso é um pouco complicado para verificar em um único regex onde a porção fracionária não é necessária. Eu incluí dois regex para mostrar isso.

Ele faz levantar a questão interessante sobre o que um "número" é. Você incluir "inf", que é válido como uma bóia em python? Ou você incluir números que são "números" mas talvez não pode ser representado em python (como números que são maiores do que o flutuador max).

Há também ambiguidades na forma como você analisar números. Por exemplo, o que acontece "--20"? É este um "número"? Será esta uma forma legal para representar "20"? Python vai deixar você fazer "var = --20" e configurá-lo para 20 (embora realmente isso é porque ele trata como uma expressão), mas float ( "- 20"). Não funciona

De qualquer forma, sem mais informações, aqui está um regex que eu acredito que abrange todos os ints e carros alegóricos como parses python-los .

# 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

Alguns valores exemplo de teste:

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

Eu também usei a função que você mencionou, mas logo percebo que strings como "Nan", "Inf" e de variação são considerados como número. Assim, proponho que você versão melhorada de sua função, que irá retornar falso sobre aqueles tipo de entrada e não falhará "1e3" 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 trata os expoentes, flutuadores, e inteiros, sem usar regex.

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

Aqui está a minha maneira simples de fazê-lo. Vamos dizer que eu estou looping através de algumas cordas e eu quero adicioná-los para uma matriz, se eles acabam por ser números.

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

Substitua o myvar.apppend com qualquer operação que você quer fazer com a corda se ele sair para ser um número. A idéia é tentar utilizar uma operação float () e usar o erro retornado para determinar se ou não a string é um número.

Você pode generalizar a técnica exceção de uma maneira útil, retornando valores mais útil do Verdadeiro e Falso. Por exemplo esta função puts cita cordas rodada, mas os números deixa sozinhos. Que é apenas o que eu precisava para um filtro rápido e sujo para fazer algumas definições de variáveis ??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:]), ')'

Eu estava trabalhando em um problema que me levou a esta discussão, a saber como converter um conjunto de dados para cordas e números da forma mais intuitiva. Percebi depois de ler o código original que o que eu precisava era diferente de duas maneiras:

1 - Eu queria um resultado inteiro se a string representado um inteiro

2 - Eu queria um número ou uma string de resultado para ficar em uma estrutura de dados

de modo que o código original adaptado para produzir 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

Tente isto.

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

função auxiliar Usuário:

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

então

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

Use seguinte ele lida com todos os 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top