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.

75
demandé sur brian d foy 2008-08-15 23:43:15

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] 
114
répondu nohat 2014-06-12 15:29:01

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}; }
23
répondu naumcho 2009-10-21 10:31:35

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";
}
20
répondu ysth 2010-09-27 17:16:12

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.

8
répondu Peter Vanroose 2012-10-17 15:18:19

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.

7
répondu andrewrk 2008-08-15 20:07:19

pas parfait, mais vous pouvez utiliser un regex:

sub isnumber 
{
    shift =~ /^-?\d+\.?\d*$/;
}
3
répondu farmerchris 2008-08-15 19:49:44

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

3
répondu jsight 2008-08-15 20:44:02

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.

2
répondu Jon Ericson 2009-10-21 10:32:08

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;
}
2
répondu fringd 2010-12-10 18:58:12

essayez ceci:

If (($x !~ /\D/) && ($x ne "")) { ... }
1
répondu CDC 2013-05-31 16:27:30

j'ai trouvé cela intéressant bien que

if ( $value + 0 eq $value) {
    # A number
    push @args, $value;
} else {
    # A string
    push @args, "'$value'";
}
1
répondu Swadhikar C 2015-10-01 14:20:31

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"; }
}
0
répondu zagrimsan 2015-12-31 13:47:24

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

0
répondu bLIGU 2016-02-26 16:55:43

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.

-1
répondu Jason Van Patten 2013-09-21 16:14:58

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;
    }
-1
répondu Mohamad Hamouday 2017-05-18 09:08:19