web-dev-qa-db-fra.com

Comment vérifier si une chaîne est un nombre (float)?

Quel est le meilleur moyen de vérifier si une chaîne peut être représentée sous forme de nombre en Python? 

La fonction que j'ai actuellement est:

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

Ce qui, non seulement est laid et lent, semble maladroit. Cependant, je n'ai pas trouvé de meilleure méthode car appeler float dans la fonction principale est encore pire. 

1349
Daniel Goldberg

Ce qui est non seulement laid et lent

Je contesterais les deux.

Une expression régulière ou une autre analyse de chaîne serait plus laide et plus lente. 

Je ne suis pas sûr que rien de plus pourrait être plus rapide que ce qui précède. Il appelle la fonction et retourne. Try/Catch n'introduit pas beaucoup de temps système car l'exception la plus courante est capturée sans recherche approfondie des images de pile.

Le problème est que toute fonction de conversion numérique a deux types de résultats

  • Un numéro, si le numéro est valide
  • Un code d'état (par exemple, via errno) ou une exception pour indiquer qu'aucun nombre valide n'a pu être analysé.

C (à titre d'exemple) corrige cela de plusieurs manières. Python le dit clairement et explicitement.

Je pense que votre code pour faire cela est parfait.

608
S.Lott

Si vous recherchez des entiers d'analyse (positifs, non signés) au lieu de flottants, vous pouvez utiliser la fonction isdigit() pour les objets chaîne.

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

Méthodes de chaîne - isdigit()

Il y a aussi quelque chose sur les chaînes Unicode, que je ne connais pas trop bien Unicode - Est décimal/décimal

1421
Zoomulator

TL; DR La meilleure solution est s.replace('.','',1).isdigit()

J'ai fait quelques points de repère en comparant les différentes approches

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 chaîne n'est pas un nombre, le bloc d'exception est assez lent. Mais plus important encore, la méthode try-except est la seule approche qui gère correctement les notations scientifiques.

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 notation flottante ".1234" n'est pas supportée par:
- 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 notation scientifique "1.000000e + 50" n'est pas supportée par:
- is_number_regex
- is_number_repl_isdigit
La notation scientifique "1e50" n'est pas supportée par:
- is_number_regex
- is_number_repl_isdigit 

EDIT: Les résultats de référence

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

où les fonctions suivantes ont été testées

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 image description here

96
Sebastian

Il y a une exception que vous voudrez peut-être prendre en compte: la chaîne 'NaN'

Si vous voulez que is_number renvoie FALSE pour 'NaN', ce code ne fonctionnera pas car Python le convertit en représentation d'un nombre qui n'est pas un nombre (parler des problèmes d'identité):

>>> float('NaN')
nan

Sinon, je devrais effectivement vous remercier pour le morceau de code que j'utilise beaucoup maintenant. :)

G.

66
gvrocha

que dis-tu de ça:

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

qui ne retournera vrai que s'il y en a un ou pas. dans la chaîne de chiffres.

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

retournera faux

edit: je viens de voir un autre commentaire ... ajouter une .replace(badstuff,'',maxnum_badstuff) pour les autres cas peut être fait. si vous passez du sel et pas des condiments arbitraires (ref: xkcd # 974 ) cela fera l'affaire: P

53
haxwithaxe

Mis à jour après qu'Alfe ait signalé qu'il n'était pas nécessaire de vérifier le flottant séparément car le complexe gère à la fois:

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

    return True

Auparavant dit: Dans de rares cas, vous pourriez également avoir besoin de vérifier les nombres complexes (par exemple 1 + 2i), qui ne peuvent pas être représentés par un flottant:

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
39
Matthew Wilcoxson

Ce qui, non seulement est laid et lent, semble maladroit.

Il faut peut-être s’y habituer, mais c’est la façon de le faire en Pythonic. Comme cela a déjà été souligné, les alternatives sont pires. Mais il y a un autre avantage à faire les choses de cette façon: le polymorphisme.

L'idée centrale derrière la frappe de canard est que "s'il marche et parle comme un canard, alors c'est un canard". Que se passe-t-il si vous décidez que vous devez sous-classer string afin de pouvoir changer la façon dont vous déterminez si quelque chose peut être converti en float? Ou si vous décidiez de tester entièrement un autre objet? Vous pouvez faire ces choses sans avoir à changer le code ci-dessus.

D'autres langues résolvent ces problèmes en utilisant des interfaces. Je vais sauvegarder l'analyse de la meilleure solution pour un autre thread. Le problème, cependant, est que python est résolument du côté du dactylographie, et vous devrez probablement vous habituer à une telle syntaxe si vous envisagez de faire beaucoup de programmation en Python (mais cela ne veut pas dire il faut aimer ça bien sûr).

Une autre chose que vous voudrez peut-être prendre en compte: Python génère assez rapidement des exceptions et les intercepte, contrairement à de nombreuses autres langues (30 fois plus rapide que .Net par exemple). Heck, le langage lui-même lève même des exceptions pour communiquer des conditions de programme normales et non exceptionnelles (chaque fois que vous utilisez une boucle for). Ainsi, je ne m'inquiéterais pas trop des aspects de performance de ce code jusqu'à ce que vous remarquiez un problème significatif.

37
Jason Baker

Pour int, utilisez ceci:

>>> "1221323".isdigit()
True

Mais pour float nous avons besoin de quelques astuces ;-). Chaque numéro de float a un point ...

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

Aussi, pour les nombres négatifs, ajoutez simplement lstrip():

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

Et maintenant nous obtenons un moyen universel:

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

Just Mimic C #

En C #, deux fonctions différentes gèrent l'analyse des valeurs scalaires:

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

float.parse ():

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

Remarque: si vous vous demandez pourquoi j'ai modifié l'exception en une erreur TypeError, voici la documentation .

float.try_parse ():

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

Remarque: vous ne voulez pas renvoyer le booléen 'False' car il s'agit toujours d'un type de valeur. Aucun n'est meilleur car il indique un échec. Bien sûr, si vous voulez quelque chose de différent, vous pouvez modifier le paramètre fail en le faisant comme vous le souhaitez .

Pour étendre float afin d'inclure 'parse ()' et 'try_parse ()', vous devez contrôler la classe 'float' pour ajouter ces méthodes.

Si vous voulez respecter les fonctions préexistantes, le code devrait ressembler à ceci:

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

SideNote: Personnellement, je préfère l'appeler Monkey Punching, parce que j'ai l'impression d'abuser du langage quand je fais cela, mais YMMV.} _

Utilisation:

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

Et le grand sage Pythonas dit au Saint-Siège Sharpisus: "Tout ce que tu peux faire, je peux faire mieux; je peux faire quelque chose de mieux que toi."

15
Evan Plaice

try: except: est en fait plus lent que les expressions régulières. Pour les chaînes de nombres valides, l'expression régulière est plus lente. La méthode appropriée dépend donc de votre contribution. 

Si vous vous trouvez dans une liaison de performance, vous pouvez utiliser un nouveau module tiers appelé fastnumbers qui fournit une fonction appelée isfloat . Divulgation complète, je suis l'auteur. J'ai inclus ses résultats dans les timings ci-dessous.


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

Comme vous pouvez le voir

  • try: except: était rapide pour une entrée numérique mais très lent pour une entrée invalide
  • regex est très efficace lorsque l'entrée est invalide
  • fastnumbers gagne dans les deux cas
15
SethMMorton

Je sais que cela est particulièrement ancien, mais j'ajouterais une réponse qui, à mon avis, couvre les informations manquantes de la réponse la plus votée et qui pourraient être très utiles à quiconque trouve ceci

Pour chacune des méthodes suivantes, connectez-les avec un compte si vous souhaitez qu'une entrée soit acceptée. (En supposant que nous utilisons des définitions vocales d'entiers plutôt que 0-255, etc.)

x.isdigit() fonctionne bien pour vérifier si x est un entier.

x.replace('-','').isdigit() fonctionne bien pour vérifier si x est un négatif. (Check-in first position)

x.replace('.','').isdigit() fonctionne bien pour vérifier si x est un nombre décimal.

x.replace(':','').isdigit() fonctionne bien pour vérifier si x est un ratio.

x.replace('/','',1).isdigit() fonctionne bien pour vérifier si x est une fraction.

12
Aruthawolf

Vous pouvez utiliser des chaînes Unicode, elles ont une méthode pour faire ce que vous voulez:

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

11
Blackzafiro

Lancer float et capturer ValueError est probablement le moyen le plus rapide, car float () est spécialement conçu pour cela. Tout ce qui nécessite une analyse syntaxique de chaîne (regex, etc.) sera probablement plus lent en raison du fait qu'il n'est pas réglé pour cette opération. Mon 0,02 $.

10
codelogic

Je voulais voir quelle méthode est la plus rapide. Globalement, les résultats les meilleurs et les plus cohérents ont été donnés par la fonction check_replace. Les résultats les plus rapides ont été donnés par la fonction check_exception, mais uniquement s'il n'y a pas eu d'exception déclenchée, ce qui signifie que son code est le plus efficace, mais que le fait de lever une exception est assez lourd.

Veuillez noter que la vérification d'une distribution réussie est la seule méthode exacte. Par exemple, cela fonctionne avec check_exception mais les deux autres fonctions de test renverront False pour un float valide:

huge_number = float('1e+100')

Voici le code de référence:

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

Voici les résultats obtenus avec Python 2.7.10 sur 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

Voici les résultats obtenus avec Python 3.6.5 sur 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

Voici les résultats avec PyPy 2.7.13 sur 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
9
Ron Reiter

Disons que vous avez des chiffres dans la chaîne . Str = "100949" .__ et que vous voulez vérifier si elle contient uniquement des chiffres

if str.isdigit():
returns TRUE or FALSE 

Documents isdigit

sinon, votre méthode fonctionne très bien pour trouver l'occurrence d'un chiffre dans une chaîne. 

7
Clayton

Donc, pour tout mettre ensemble, en cherchant Nan, l'infini et les nombres complexes (il semblerait qu'ils soient spécifiés avec j, pas i, c'est-à-dire 1 + 2j), il en résulte:

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

Votre code me semble bien.

Vous pensez peut-être que le code est "maladroit" à cause de l'utilisation d'exceptions? Notez que les programmeurs Python ont tendance à utiliser les exceptions de manière libérale quand il améliore la lisibilité du code, grâce à sa faible performance.

5
Dubhead

Je devais déterminer si une chaîne était convertie en types de base (float, int, str, bool). Après ne rien trouver sur Internet, j'ai créé ceci:

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)

Exemple

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       

Vous pouvez capturer le type et l'utiliser 

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

J'ai fait un test de vitesse. Disons que si la chaîne est susceptible d'être un nombre, la stratégie try/except est la plus rapide possible.Si la chaîne est peu probable d'être un nombre et vous sont intéressés par Integer check, cela vaut la peine de faire un test (isdigit plus rubrique '-'). Si vous souhaitez vérifier le numéro flottant, vous devez utiliser le code try/except sans échappement.

4
FxIII

L'entrée peut être comme suit:

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


1-Entrée générale:

L'entrée de cette fonction peut être tout!

Détermine si la variable donnée est numérique. Les chaînes numériques se composent d'un signe optionnel, d'un nombre quelconque de chiffres, d'une partie décimale optionnelle et d'une partie exponentielle optionnelle. Ainsi, + 0123.45e6 est une valeur numérique valide. La notation hexadécimale (par exemple 0xf4c3b00c) et binaire (par exemple 0b10100111001) n'est pas autorisée.

is_numeric fonction

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

tester:

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

is_float fonction

Détermine si la variable donnée est float. Les chaînes float consistent en un signe optionnel, un nombre quelconque de chiffres, ...

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

tester:

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

qu'est-ce que ast ?


2- Si vous êtes sûr que le contenu de la variable est String:

utilisez str.isdigit () method

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

Entrée 3-numérique:

detect int value:

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

detect float:

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

RyanN suggère

Si vous voulez renvoyer False pour NaN et Inf, changez la ligne en x = float (s); retourne (x == x) et (x - 1! = x). Cela devrait retourner Vrai pour tous les flottants sauf Inf et NaN

Mais cela ne fonctionne pas tout à fait, car pour des flottants suffisamment grands, x-1 == x renvoie true. Par exemple, 2.0**54 - 1 == 2.0**54

3
philh

J'ai également utilisé la fonction que vous avez mentionnée, mais je remarque rapidement que les chaînes telles que "Nan", "Inf" et leurs variations sont considérées comme des nombres. Je vous propose donc une version améliorée de votre fonction, qui retournera false sur ce type d'entrée et n'échouera pas avec les 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
1
mathfac

Vous pouvez généraliser la technique d'exception de manière utile en renvoyant des valeurs plus utiles que True et False. Par exemple, cette fonction met les guillemets autour des guillemets tout en laissant les nombres seuls. Ce qui est juste ce dont j'avais besoin pour un filtre rapide et sale pour faire des définitions variables pour 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:]), ')'
0
Thruston

Essaye ça.

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

Fonction d'assistance utilisateur:

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

puis

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)])
0
Samantha Atkins

Si vous voulez savoir si la chaîne entière peut être représentée sous forme de nombre, vous voudrez utiliser une expression rationnelle (ou peut-être convertir le flottant en chaîne et la comparer à la chaîne source, mais je suppose ce n'est pas très rapide).

0
m_eiman

Je pense que votre solution est bien.

Cela dit, il y a beaucoup de hausses d'expressions rationnelles à propos de ces réponses qui, à mon avis, sont injustifiées, les expressions rationnelles peuvent être raisonnablement propres, correctes et rapides. Cela dépend vraiment de ce que vous essayez de faire. La question initiale était de savoir comment "vérifier si une chaîne de caractères peut être représentée sous forme de nombre (float)" (selon votre titre). Vous voudrez probablement utiliser la valeur numeric/float une fois que vous avez vérifié sa validité, auquel cas votre option try/except est très utile. Mais si, pour une raison quelconque, vous voulez simplement valider qu'un chaîne est un nombre , une expression rationnelle fonctionne également, mais il est difficile d'obtenir une correction. Je pense que la plupart des réponses rationnelles jusqu’à présent, par exemple, n’analysent pas correctement les chaînes sans une partie entière (telle que ".7") qui est un float pour Python. Et c’est un peu délicat à vérifier dans une seule expression rationnelle où la partie fractionnaire n’est pas requise. J'ai inclus deux regex pour montrer cela.

Cela soulève la question intéressante de savoir ce qu'est un "nombre". Incluez-vous "inf" qui est valide en tant que float en python? Ou incluez-vous des nombres qui sont des "nombres" mais qui ne peuvent peut-être pas être représentés en python (tels que des nombres plus grands que le flottant max).

Il y a aussi des ambiguïtés dans la façon dont vous analysez les nombres. Par exemple, qu'en est-il de "--20"? Est-ce un "numéro"? Est-ce une façon légale de représenter "20"? Python vous laissera faire "var = --20" et le mettra à 20 (bien que c'est vraiment parce qu'il le traite comme une expression), mais float ("- 20") ne fonctionne pas.

En tout cas, sans plus d’informations, voici une regex qui, je crois, couvre tous les ints et floats comme Python les analyse .

# 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

Quelques exemples de valeurs de test:

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
0

Ce code gère les exposants, les flottants et les entiers sans utiliser regex.

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

Voici ma façon simple de le faire. Disons que je boucle certaines chaînes et que je veux les ajouter à un tableau si elles s'avèrent être des nombres.

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

Remplacez myvar.apppend par l'opération de votre choix si elle s'avère être un nombre. L'idée est d'essayer d'utiliser une opération float () et d'utiliser l'erreur renvoyée pour déterminer si la chaîne est un nombre ou non.

0
Anil

Je travaillais sur un problème qui m'a amené à ce fil, à savoir comment convertir une collection de données en chaînes et en nombres de la manière la plus intuitive possible. Après avoir lu le code original, j'ai réalisé que ce dont j'avais besoin était différent de deux manières:

1 - Je voulais un résultat entier si la chaîne représentait un entier

2 - Je voulais qu'un nombre ou un résultat de chaîne collent dans une structure de données

alors j'ai adapté le code original pour produire ce dérivé:

def string_or_number(s):
    try:
        z = int(s)
        return z
    except ValueError:
        try:
            z = float(s)
            return z
        except ValueError:
            return s
0
user1508746
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
0
xin.chen