¿Cómo puedo saber si una variable tiene un valor numérico en Perl?
numbers (15)
¿Hay alguna manera simple en Perl que me permita determinar si una variable dada es numérica? Algo como:
if (is_number($x))
{ ... }
sería ideal Una técnica que no lanzará advertencias cuando se usa el -w
es sin duda preferida.
Consulte el módulo CPAN Regexp::Common . Creo que hace exactamente lo que necesita y maneja todos los casos extremos (por ejemplo, números reales, notación científica, etc.). p.ej
use Regexp::Common;
if ($var =~ /$RE{num}{real}/) { print q{a number}; }
Encontré esto interesante aunque
if ( $value + 0 eq $value) {
# A number
push @args, $value;
} else {
# A string
push @args, "''$value''";
}
Esta función funciona para mí:
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;
}
La pregunta original era cómo decir si una variable era numérica, no si "tiene un valor numérico".
Hay unos pocos operadores que tienen modos de operación separados para operandos numéricos y de cadena, donde "numérico" significa cualquier cosa que originalmente era un número o que alguna vez se usó en un contexto numérico (por ejemplo, en $x = "123"; 0+$x
, antes de la suma, $x
es una cadena, luego se considera numérica).
Una forma de decir es esto:
if ( length( do { no warnings "numeric"; $x & "" } ) ) {
print "$x is numeric/n";
}
No creo que haya nada integrado para hacerlo. Por más de lo que siempre quiso ver sobre el tema, consulte Perlmonks sobre Detección numérica
No es perfecto, pero puedes usar una expresión regular:
sub isnumber
{
shift =~ /^-?/d+/.?/d*$/;
}
Personalmente, creo que el camino a seguir es confiar en el contexto interno de Perl para que la solución sea a prueba de balas. Una buena expresión regular podría coincidir con todos los valores numéricos válidos y ninguno de los no numéricos (o viceversa), pero como hay una forma de emplear la misma lógica que usa el intérprete, debería ser más seguro confiar en eso directamente.
Como tiendo a ejecutar mis scripts con -w
, tuve que combinar la idea de comparar el resultado de "valor más cero" con el valor original con el enfoque basado en no warnings
de @ysth:
do {
no warnings "numeric";
if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; }
}
Por lo general, la validación del número se realiza con expresiones regulares. Este código determinará si algo es numérico y también buscará variables indefinidas para no lanzar advertencias:
sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?/d+$/;
}
sub is_float {
defined $_[0] && $_[0] =~ /^[+-]?/d+(/./d+)?$/;
}
Aquí hay un poco de material de lectura que deberías mirar.
Prueba esto:
If (($x !~ //D/) && ($x ne "")) { ... }
Puede usar expresiones regulares para determinar si $ foo es un número (o no).
Eche un vistazo aquí: ¿Cómo puedo determinar si un escalar es un número
Se puede encontrar una expresión regular un poco más robusta en Regexp::Common .
Parece que quieres saber si Perl cree que una variable es numérica. Aquí hay una función que atrapa esa advertencia:
sub is_number{
my $n = shift;
my $ret = 1;
$SIG{"__WARN__"} = sub {$ret = 0};
eval { my $x = $n + 1 };
return $ret
}
Otra opción es desactivar la advertencia localmente:
{
no warnings "numeric"; # Ignore "isn''t numeric" warning
... # Use a variable that might not be numeric
}
Tenga en cuenta que las variables no numéricas se convertirán en silencio a 0, que es probablemente lo que quería de todos modos.
Una respuesta simple (y quizás simplista) a la pregunta es que el contenido de $x
numeric es el siguiente:
if ($x eq $x+0) { .... }
Hace una comparación textual de los $x
originales con los $x
convertidos a un valor numérico.
Use Scalar::Util::looks_like_number()
que usa la función interna de la API de Perl C looks_like_number (), que es probablemente la forma más eficiente de hacerlo. Tenga en cuenta que las cadenas "inf" e "infinito" se tratan como números.
Ejemplo:
#!/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";
}
Da esta salida:
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
ver también:
[perldoc Scalar::Util][1]
[perldoc perlapi][2]
if (definido $ x && $ x! ~ m / / D /) {} o $ x = 0 si! $ x; if ($ x! ~ m / / D /) {}
Esta es una pequeña variación en la respuesta de Veekay, pero déjame explicar mi razonamiento para el cambio.
Realizar una expresión regular en un valor indefinido provocará un error en el volumen y provocará que el código salga en muchos entornos, sino en la mayoría. Probar si el valor está definido o establecer un caso predeterminado como lo hice en el ejemplo alternativo antes de ejecutar la expresión, como mínimo, guardará su registro de errores.
rexep no es perfecto ... esto es:
use Try::Tiny;
sub is_numeric {
my ($x) = @_;
my $numeric = 1;
try {
use warnings FATAL => qw/numeric/;
0 + $x;
}
catch {
$numeric = 0;
};
return $numeric;
}