Quelle est la meilleure façon de vérifier si une chaîne peut être représentée sous forme de nombre en Python?
La fonction que j'ai actuellement en ce moment 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
la fonction principale est encore pire.
python
casting
floating-point
type-conversion
Daniel Goldberg
la source
la source
x = float('0.00'); if x: use_float(x);
vous avez maintenant un bug dans votre code. Des valeurs véridiques sont la raison pour laquelle ces fonctions déclenchent une exception plutôt que de revenirNone
en premier lieu. Une meilleure solution consiste simplement à éviter la fonction utilitaire et à entourer l'appel pour qu'il flotte dans untry catch
lorsque vous souhaitez l'utiliser.Réponses:
Je contesterais les deux.
Une expression rationnelle ou une autre méthode d'analyse de chaîne serait plus laide et plus lente.
Je ne suis pas sûr que quoi que ce soit pourrait être plus rapide que ce qui précède. Il appelle la fonction et retourne. Try / Catch n'introduit pas beaucoup de surcharge car l'exception la plus courante est interceptée sans une recherche approfondie des trames de pile.
Le problème est que toute fonction de conversion numérique a deux types de résultats
C (à titre d'exemple) contourne cela de plusieurs façons. Python le présente clairement et explicitement.
Je pense que votre code pour ce faire est parfait.
la source
try
clause, donc je mettrais lereturn True
dans uneelse
clause de latry
. L'une des raisons est qu'avec le code dans la question, si je devais le réviser, je devrais vérifier que la deuxième instruction de latry
clause ne peut pas déclencher une ValueError: accordée, cela ne nécessite pas trop de temps ou de puissance cérébrale, mais pourquoi en utiliser quand aucun n'est nécessaire?IsNumeric()
je me retrouve avec un try / catch ou un autre enveloppant un try / catch. Ughif is_number(s): x = float(x) else: // fail
s'agit du même nombre de lignes de code que letry: x = float(x) catch TypeError: # fail
. Cette fonction utilitaire est une abstraction totalement inutile.Si vous recherchez des entiers (positifs, non signés) au lieu de flottants, vous pouvez utiliser la
isdigit()
fonction pour les objets chaîne.Méthodes de chaîne -
isdigit()
: Python2 , Python3Il y a aussi quelque chose sur les chaînes Unicode, que je ne connais pas trop Unicode - est décimal / décimal
la source
isdigit()
etint()
ont des opinions différentes sur ce qu'est un entier, par exemple, pour le caractère Unicodeu'\u00b9'
:u'¹'.isdigit()
isTrue
butint(u'¹')
raises ValueError.TL; DR La meilleure solution est
s.replace('.','',1).isdigit()
J'ai fait quelques repères comparant les différentes approches
Si la chaîne n'est pas un nombre, le bloc except est assez lent. Mais plus important encore, la méthode try-except est la seule approche qui gère correctement les notations scientifiques.
La notation flottante ".1234" n'est pas prise en charge par:
- is_number_regex
La notation scientifique "1.000000e + 50" n'est pas prise en charge par:
- is_number_regex
- is_number_repl_isdigit
La notation scientifique "1e50" n'est pas prise en charge par:
- is_number_regex
- is_number_repl_isdigit
EDIT: Les résultats de référence
où les fonctions suivantes ont été testées
la source
s.replace('.','',1).isdigit()
) devrait apparaître au début de cette réponse. En tout cas, ce doit être celui qui est accepté. Merci!'1.5e-9'
ou sur les négatifs.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 sa représentation d'un nombre qui n'est pas un nombre (parler de problèmes d'identité):
Sinon, je devrais en fait vous remercier pour le morceau de code que j'utilise maintenant largement. :)
G.
la source
NaN
pourrait être une bonne valeur à renvoyer (plutôt queFalse
) si le texte passé n'est pas en fait une représentation d'un nombre. Le vérifier est une sorte de douleur (lefloat
type de Python a vraiment besoin d'une méthode pour cela) mais vous pouvez l'utiliser dans les calculs sans produire d'erreur, et il suffit de vérifier le résultat.'inf'
. L'uninf
ou l' autreNaN
peut également être précédé d'un+
ou-
et être toujours accepté.x-1 == x
est vrai pour les grands flotteurs plus petits queinf
. À partir de Python 3.2, vous pouvez utilisermath.isfinite
pour tester des nombres qui ne sont ni NaN ni infinis, ou vérifier les deuxmath.isnan
etmath.isinf
avant cela.que dis-tu de ça:
qui ne retournera vrai que s'il y en a un ou pas '.' dans la chaîne de chiffres.
retournera faux
edit: vient de voir un autre commentaire ... l'ajout d'un
.replace(badstuff,'',maxnum_badstuff)
pour d'autres cas peut être fait. si vous passez du sel et non des condiments arbitraires (ref: xkcd # 974 ) cela fera l'affaire: Pla source
1.234e56
(qui pourraient également être écrits comme+1.234E+56
et plusieurs autres variantes).re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')
devrait faire un meilleur travail pour déterminer un nombre (mais pas tous, je ne le prétends pas). Je ne recommande pas d'utiliser cela, bien mieux d'utiliser le code original de l'interrogateur.Cela peut prendre un certain temps pour s'y habituer, mais c'est la façon pythonique de le faire. 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 la chaîne afin de pouvoir changer la façon dont vous déterminez si quelque chose peut être converti en flottant? Ou si vous décidez de tester un autre objet entièrement? 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 enregistrer l'analyse de la meilleure solution pour un autre thread. Le point, cependant, est que python est décidément du côté du typage du canard de l'équation, et vous devrez probablement vous habituer à une syntaxe comme celle-ci si vous prévoyez de faire beaucoup de programmation en Python (mais cela ne signifie pas vous devez l'aimer bien sûr).
Une autre chose que vous voudrez peut-être prendre en considération: Python lance et capture des exceptions assez rapidement par rapport à beaucoup d'autres langages (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 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 important.
la source
hasattr()
lequel est juste ungetattr()
appel enveloppé dans untry/except
. Pourtant, la gestion des exceptions est plus lente que le contrôle de flux normal, donc l'utiliser pour quelque chose qui va être vrai la plupart du temps peut entraîner une baisse des performances.Mis à jour après qu'Alfe ait souligné que vous n'avez pas besoin de vérifier séparément le flotteur car les poignées complexes gèrent les deux:
Dit précédemment: Dans certains cas rares, vous devrez peut-être également vérifier les nombres complexes (par exemple 1 + 2i), qui ne peuvent pas être représentés par un flottant:
la source
float()
supprimer complètement le contenu et vérifier que l'complex()
appel a réussi. Tout analysé parfloat()
peut être analysé parcomplex()
.complex('(01989)')
reviendra(1989+0j)
. Maisfloat('(01989)')
échouera. Je pense donc que l'utilisationcomplex
n'est pas une bonne idée.Pour
int
utiliser ceci:Mais pour
float
nous avons besoin de quelques astuces ;-). Chaque nombre flottant a un point ...Pour les nombres négatifs, ajoutez simplement
lstrip()
:Et maintenant, nous obtenons un moyen universel:
la source
1.234e56
et similaires. De plus, je serais intéressé de savoir comment vous découvririez que ce99999999999999999999e99999999999999999999
n'est pas un nombre. Essayer de l'analyser le découvre rapidement.Just Mimic C #
En C #, il existe deux fonctions différentes qui gèrent l'analyse des valeurs scalaires:
float.parse ():
Remarque: Si vous vous demandez pourquoi j'ai changé l'exception en TypeError, voici la documentation .
float.try_parse ():
Remarque: vous ne voulez pas renvoyer le booléen 'False' car il s'agit toujours d'un type de valeur. Aucune n'est meilleure car elle indique un échec. Bien sûr, si vous voulez quelque chose de différent, vous pouvez changer le paramètre d'échec en ce que vous voulez.
Pour étendre float pour inclure les 'parse ()' et 'try_parse ()', vous devrez monkeypatch la classe 'float' pour ajouter ces méthodes.
Si vous voulez respecter les fonctions préexistantes, le code devrait ressembler à ceci:
SideNote: Personnellement, je préfère l'appeler Monkey Punching parce que j'ai l'impression d'abuser de la langue quand je fais ça, mais YMMV.
Usage:
Et le grand Sage Pythonas a dit au Saint-Siège Sharpisus: "Tout ce que vous pouvez faire, je peux le faire mieux; je peux faire quelque chose de mieux que vous."
la source
!
au lieu denot
peut être une erreur mineure, mais vous ne pouvez certainement pas attribuer d'attributs aufloat
CPython intégré .Pour les chaînes de non-nombres,
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. Ainsi, la méthode appropriée dépend de votre saisie.Si vous constatez que vous êtes dans une liaison de performances, 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 horaires ci-dessous.
Comme vous pouvez le voir
try: except:
était rapide pour l'entrée numérique mais très lent pour une entrée invalidefastnumbers
gagne dans les deux casla source
prep_code_basis
etprep_code_re_method
aurait empêché mon erreur.isfloat
fonction?str(s).strip('-').replace('.','',1).isdigit()
est environ 10 fois plus lente!Je sais que cela est particulièrement ancien, mais j'ajouterais une réponse qui, je crois, couvre les informations manquantes de la réponse la plus votée qui pourraient être très précieuses pour tous ceux qui trouveraient ceci:
Pour chacune des méthodes suivantes, connectez-les avec un nombre si vous avez besoin d'une entrée pour être acceptée. (En supposant que nous utilisons des définitions vocales d'entiers plutôt que de 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 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 rapport.x.replace('/','',1).isdigit()
fonctionne bien pour vérifier si x est une fraction.la source
x.replace('/','',1).isdigit()
sinon les dates telles que 4/7/2017 seraient mal interprétées comme des nombres.Cette réponse fournit un guide étape par étape ayant une fonction avec des exemples pour trouver la chaîne:
Vérifiez si la chaîne est un entier positif
Vous pouvez utiliser
str.isdigit()
pour vérifier si une chaîne donnée est un entier positif .Exemples de résultats:
Vérifiez que la chaîne est positive / négative - entier / flottant
str.isdigit()
renvoieFalse
si la chaîne est un nombre négatif ou un nombre flottant. Par exemple:Si vous souhaitez également vérifier les entiers négatifs et
float
, vous pouvez écrire une fonction personnalisée pour la vérifier comme suit:Exemple d'exécution:
Jeter les chaînes "NaN" (pas un nombre) tout en vérifiant le nombre
Les fonctions ci-dessus
True
renverront la chaîne "NAN" (pas un nombre) car pour Python, c'est un flottant valide qui représente que ce n'est pas un nombre. Par exemple:Afin de vérifier si le nombre est "NaN", vous pouvez utiliser
math.isnan()
comme:Ou si vous ne voulez pas importer de bibliothèque supplémentaire pour vérifier cela, vous pouvez simplement la vérifier en la comparant avec elle-même en utilisant
==
. Python revientFalse
lorsquenan
float est comparé à lui-même. Par exemple:Par conséquent, la fonction
is_number
False
"NaN"
ci-dessus peut être mise à jour pour revenir en tant que:Exemple d'exécution:
PS: Chaque opération pour chaque vérification en fonction du type de numéro s'accompagne de frais généraux supplémentaires. Choisissez la version de
is_number
fonction qui correspond à vos besoins.la source
Caster pour flotter et attraper ValueError est probablement le moyen le plus rapide, car float () est spécifiquement destiné à cela. Tout autre élément nécessitant une analyse de chaîne (regex, etc.) sera probablement plus lent car il n'est pas réglé pour cette opération. Mon 0,02 $.
la source
Vous pouvez utiliser des chaînes Unicode, elles ont une méthode pour faire exactement ce que vous voulez:
Ou:
http://www.tutorialspoint.com/python/string_isnumeric.htm
http://docs.python.org/2/howto/unicode.html
la source
s.isdecimal()
vérifie si las
chaîne est un entier non négatif.s.isnumeric()
inclut des caractères quiint()
rejettent.Je voulais voir quelle méthode est la plus rapide. Dans l'ensemble, les résultats les meilleurs et les plus cohérents ont été donnés par la
check_replace
fonction. Les résultats les plus rapides ont été donnés par lacheck_exception
fonction, mais uniquement si aucune exception n'a été déclenchée - ce qui signifie que son code est le plus efficace, mais la surcharge de lever une exception est assez grande.Veuillez noter que la vérification d'une conversion réussie est la seule méthode qui est précise, par exemple, cela fonctionne avec
check_exception
mais les deux autres fonctions de test renverront False pour un flottant valide:Voici le code de référence:
Voici les résultats avec Python 2.7.10 sur un MacBook Pro 13 2017:
Voici les résultats avec Python 3.6.5 sur un MacBook Pro 13 2017:
Voici les résultats avec PyPy 2.7.13 sur un MacBook Pro 13 2017:
la source
Donc, pour mettre tout cela ensemble, en vérifiant les nombres Nan, infini et complexes (il semblerait qu'ils soient spécifiés avec j, pas i, c'est-à-dire 1 + 2j), il en résulte:
la source
L'entrée peut être la suivante:
a="50"
b=50
c=50.1
d="50.1"
1-Entrée générale:
L'entrée de cette fonction peut être tout!
Recherche si la variable donnée est numérique. Les chaînes numériques se composent d'un signe facultatif, d'un nombre quelconque de chiffres, d'une partie décimale facultative et d'une partie exponentielle facultative. 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.
Fonction is_numeric
tester:
Fonction is_float
Recherche si la variable donnée est flottante. les chaînes flottantes se composent d'un signe facultatif, d'un nombre quelconque de chiffres, ...
tester:
ce qui est ast ?
2- Si vous êtes sûr que le contenu de la variable est String :
utiliser la méthode str.isdigit ()
3 entrées numériques:
détecter la valeur int:
détecter flotteur:
la source
ast
"?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 n'est pas susceptible d'être un nombre et que vous êtes intéressé par le contrôle entier , cela vaut la peine de faire un test (isdigit plus en-tête «-»). Si vous souhaitez vérifier le nombre flottant, vous devez utiliser le code try / except sans échappement.
la source
J'avais besoin de déterminer si une chaîne était convertie en types de base (float, int, str, bool). Après n'avoir rien trouvé sur Internet, j'ai créé ceci:
Exemple
Vous pouvez capturer le type et l'utiliser
la source
RyanN suggère
Mais cela ne fonctionne pas tout à fait, car pour des flotteurs suffisamment grands,
x-1 == x
renvoie true. Par exemple,2.0**54 - 1 == 2.0**54
la source
Je pense que votre solution est très bien, mais il y a une implémentation regexp correcte.
Il semble y avoir beaucoup de haine d'expression régulière envers ces réponses, ce qui, à mon avis, n'est pas justifié, les expressions régulières 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 peut être représentée sous la forme d'un nombre (float)" (selon votre titre). Vraisemblablement, vous voudrez utiliser la valeur numérique / flottante une fois que vous avez vérifié qu'elle est valide, auquel cas votre essai / sauf a beaucoup de sens. Mais si, pour une raison quelconque, vous voulez simplement valider qu'une chaîne est un nombrealors une expression régulière fonctionne également bien, mais il est difficile de se corriger. Je pense que la plupart des réponses d'expressions régulières jusqu'à présent, par exemple, n'analysent pas correctement les chaînes sans une partie entière (comme ".7") qui est un flottant en ce qui concerne python. Et c'est un peu difficile à vérifier dans une seule expression régulière où la partie fractionnaire n'est pas requise. J'ai inclus deux regex pour le montrer.
Cela soulève la question intéressante de savoir ce qu'est un «nombre». Incluez-vous "inf" qui est valide comme flottant 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 "nombre"? Est-ce une manière légale de représenter "20"? Python vous permettra de faire "var = --20" et de le mettre à 20 (bien que ce soit vraiment parce qu'il le traite comme une expression), mais float ("- 20") ne fonctionne pas.
Quoi qu'il en soit, sans plus d'informations, voici une expression régulière qui, je crois, couvre tous les entiers et flotte au fur et à mesure que python les analyse .
Quelques exemples de valeurs de test:
L'exécution du code d'analyse comparative dans la réponse de @ ron-reiter montre que cette expression régulière est en fait plus rapide que l'expression régulière et est beaucoup plus rapide à gérer les mauvaises valeurs que l'exception, ce qui est logique. Résultats:
la source
la source
1e6
représenter un nombre?Voici ma façon simple de le faire. Disons que je fais une boucle sur certaines chaînes et que je veux les ajouter à un tableau si elles se révèlent être des nombres.
Remplacez myvar.apppend par l'opération que vous souhaitez effectuer avec la chaîne s'il s'avère qu'il s'agit d'un nombre. L'idée est d'essayer d'utiliser une opération float () et d'utiliser l'erreur retournée pour déterminer si la chaîne est ou non un nombre.
la source
J'ai également utilisé la fonction que vous avez mentionnée, mais bientôt je remarque que les chaînes comme "Nan", "Inf" et sa variation 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 ne manquera pas les variantes "1e3":
la source
Ce code gère les exposants, les flottants et les entiers, sans utiliser d'expression régulière.
la source
Fonction d'assistance utilisateur:
puis
la source
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 des guillemets autour des chaînes mais laisse les nombres seuls. C'est exactement ce dont j'avais besoin pour un filtre rapide et sale pour faire des définitions de variables pour R.
la source
Je travaillais sur un problème qui m'a conduit à ce fil, à savoir comment convertir une collection de données en chaînes et en nombres de la manière la plus intuitive. J'ai réalisé après avoir lu le code original 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 colle dans une structure de données
j'ai donc adapté le code original pour produire ce dérivé:
la source
Essaye ça.
la source
is_number('10')
la source