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.
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
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.
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
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
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()
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.
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
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
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.
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
En C #, deux fonctions différentes gèrent l'analyse des valeurs scalaires:
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."
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 invalidefastnumbers
gagne dans les deux casJe 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.
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
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 $.
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
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
sinon, votre méthode fonctionne très bien pour trouver l'occurrence d'un chiffre dans une chaîne.
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
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.
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)
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.
L'entrée peut être comme suit:
a="50"
b=50
c=50.1
d="50.1"
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 ?
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
detect int value:
>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>>
detect float:
>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True
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
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
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:]), ')'
Essaye ça.
def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False
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)])
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).
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
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
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.
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
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