Comment savoir si une variable a une valeur numérique dans Perl?
Est-il un moyen simple en Perl qui me permettra de déterminer si une variable est numérique? Quelque chose du genre:
if (is_number($x))
{ ... }
serait idéal. Une technique qui ne lance pas d'avertissement lorsque l'interrupteur -w
est utilisé est certainement préférable.
15 réponses
utilise Scalar::Util::looks_like_number()
qui utilise la fonction looks_like_number() de L'API Perl C, ce qui est probablement le moyen le plus efficace de le faire.
Notez que les chaînes "inf" et "infinity" sont traitées comme des nombres.
exemple:
#!/usr/bin/perl
use warnings;
use strict;
use Scalar::Util qw(looks_like_number);
my @exprs = qw(1 5.25 0.001 1.3e8 foo bar 1dd inf infinity);
foreach my $expr (@exprs) {
print "$expr is", looks_like_number($expr) ? '' : ' not', " a number\n";
}
donne cette sortie:
1 is a number
5.25 is a number
0.001 is a number
1.3e8 is a number
foo is not a number
bar is not a number
1dd is not a number
inf is a number
infinity is a number
voir aussi:
[perldoc Scalar::Util][1]
[perldoc perlapi][2]
découvrez le module CPAN Regexp::Common . Je pense qu'il fait exactement ce dont vous avez besoin et traite tous les cas de bord (par exemple, les nombres réels, la notation scientifique, etc). par exemple
use Regexp::Common;
if ($var =~ /$RE{num}{real}/) { print q{a number}; }
la question initiale était de savoir comment dire si une variable était numérique, et non si elle"avait une valeur numérique".
il y a quelques opérateurs qui ont des modes de fonctionnement distincts pour les opérandes numériques et les opérandes à chaîne, où" numérique "signifie Tout ce qui était à l'origine un nombre ou qui a été utilisé dans un contexte numérique (par exemple dans $x = "123"; 0+$x
, avant l'ajout, $x
est une chaîne, après il est considéré comme numérique).
une façon de dire est ceci:
if ( length( do { no warnings "numeric"; $x & "" } ) ) {
print "$x is numeric\n";
}
une réponse simple (et peut-être simpliste) à la question est le contenu de $x
numérique est la suivante:
if ($x eq $x+0) { .... }
il fait une comparaison textuelle de l'original $x
avec le $x
converti en valeur numérique.
habituellement la validation de nombre est faite avec des expressions régulières. Ce code va déterminer si quelque chose est numérique ainsi que de vérifier les variables non définies comme de ne pas jeter des avertissements:
sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}
sub is_float {
defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
}
Voici quelques matériels de lecture vous devriez regarder.
pas parfait, mais vous pouvez utiliser un regex:
sub isnumber
{
shift =~ /^-?\d+\.?\d*$/;
}
Je ne crois pas qu'il y ait quelque chose de construit pour le faire. Pour plus que vous avez toujours voulu voir sur le sujet, voir Perlmonks sur la Détection Numérique
un regex légèrement plus robuste peut être trouvé dans Regexp::commun .
On dirait que vous voulez savoir si Perl pense qu'une variable est numérique. Voici une fonction qui piège cet avertissement:
sub is_number{
my $n = shift;
my $ret = 1;
$SIG{"__WARN__"} = sub {$ret = 0};
eval { my $x = $n + 1 };
return $ret
}
une autre option consiste à désactiver l'avertissement localement:
{
no warnings "numeric"; # Ignore "isn't numeric" warning
... # Use a variable that might not be numeric
}
notez que les variables non numériques seront converties silencieusement en 0, ce qui est probablement ce que vous vouliez de toute façon.
rexep pas parfait... c'est:
use Try::Tiny;
sub is_numeric {
my ($x) = @_;
my $numeric = 1;
try {
use warnings FATAL => qw/numeric/;
0 + $x;
}
catch {
$numeric = 0;
};
return $numeric;
}
j'ai trouvé cela intéressant bien que
if ( $value + 0 eq $value) {
# A number
push @args, $value;
} else {
# A string
push @args, "'$value'";
}
personnellement, je pense que le chemin à suivre est de s'appuyer sur le contexte interne de Perl pour rendre la solution à l'épreuve des balles. Un bon regexp pourrait correspondre à toutes les valeurs numériques valides et aucune des valeurs non numériques (ou vice versa), mais comme il y a une façon d'employer la même logique que l'interpréteur utilise, il devrait être plus sûr de s'y fier directement.
comme j'ai tendance à exécuter mes scripts avec -w
, j'ai dû combiner l'idée de comparer le résultat de "valeur plus zéro" à la valeur originale avec l'approche no warnings
de @ysth:
do {
no warnings "numeric";
if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; }
}
vous pouvez utiliser des Expressions régulières pour déterminer si $foo est un nombre (ou non).
Regardez ici: Comment puis-je déterminer si un scalaire est un nombre
si ( défini $x && $x !~ m / \D/ ) {} ou $x = 0 si ! $x; if ( $x !~ m/\D/) {}
il s'agit d'une légère variation de la réponse de Veekay, mais permettez-moi d'expliquer mon raisonnement pour le changement.
L'exécution d'un regex sur une valeur non définie provoquera un spew d'erreur et provoquera la sortie du code dans beaucoup sinon la plupart des environnements. Tester si la valeur est définie ou définir un cas par défaut comme je l'ai fait dans l'exemple alternatif avant d'exécuter l'expression va, au minimum, enregistrez votre journal des erreurs.
cette fonction fonctionne pour moi:
sub IS_Integer()
{
my $Text = shift;
my $Integer = 0;
if ($Text =~ /\D/)
{
$Integer = 1;
}
if ($Text =~ /^\d+$/)
{
$Integer = 1;
}
if ($Text =~ /^-?\d+$/)
{
$Integer = 1;
}
if ($Text =~ /^[+-]?\d+$/)
{
$Integer = 1;
}
if ($Text =~ /^-?\d+\.?\d*$/)
{
$Integer = 1;
}
if ($Text =~ /^-?(?:\d+(?:\.\d*)?&\.\d+)$/)
{
$Integer = 1;
}
if ($Text =~ /^([+-]?)(?=\d&\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
{
$Integer = 1;
}
return $Integer;
}