Use Scalar::Util::looks_like_number()
que usa la función looks_like_number () de la API interna de Perl C, que es probablemente la forma más eficiente de hacer esto. Tenga en cuenta que las cadenas "inf" e "infinity" se tratan como números.
Ejemplo:
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 perlapi
nos dice: Prueba si el contenido de un SV parece un número (o es un número). "Inf" e "Infinity" se tratan como números (por lo que no emitirán una advertencia no numérica), incluso si su atof () no los asimila. Difícilmente una especificación comprobable ...0x12
se no considera los números de esta prueba.Consulte el módulo CPAN Regexp :: Common . Creo que hace exactamente lo que necesitas 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}; }
fuente
La pregunta original era cómo saber si una variable era numérica, no si "tiene un valor numérico".
Hay algunos 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 (p. Ej.
$x = "123"; 0+$x
, En , antes de la adición,$x
es una cadena, luego se considera numérico).Una forma de saberlo es esta:
if ( length( do { no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
Si la función bit a bit está habilitada, eso hace que
&
solo sea un operador numérico y agrega un&.
operador de cadena separado , debe deshabilitarlo:if ( length( do { no if $] >= 5.022, "feature", "bitwise"; no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
(bit a bit está disponible en perl 5.022 y superior, y está habilitado de forma predeterminada si usted
use 5.028;
o superior).fuente
sub numeric { $obj = shift; no warnings "numeric"; return eval('length($obj & "")'); }
my $obj = shift;
. ¿Por qué la evaluación?my $obj = shift
, por supuesto, simplemente no lo transferí correctamente de mi código al comentario, lo edité un poco. Sin embargo,sub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }
produce el mismo error. Por supuesto, tener una variable global clandestina explicaría el comportamiento, es exactamente lo que esperaría en ese caso, pero desafortunadamente, no es tan simple. Además, eso sería capturado porstrict
&warnings
. Probé la evaluación en un intento bastante desesperado por deshacerme del error, y funcionó. Sin razonamientos más profundos, solo prueba y error.sub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }
print numeric("w") . "\n"; #=>0
,print numeric("x") . "\n"; #=>0
,print numeric("1") . "\n"; #=>0
,print numeric(3) . "\n"; #=>1
,print numeric("w") . "\n"; #=>1
. Si pones un eval ('') alrededor de la longitud, la última impresión daría un 0, como debería. Imagínate.Una respuesta simple (y tal vez simplista) a la pregunta es que el contenido de
$x
numérico es el siguiente:if ($x eq $x+0) { .... }
Hace una comparación textual del original
$x
con el$x
convertido a un valor numérico.fuente
$x eq (($x+0)."")
sin embargo, un problema peor es que bajo esta función, "1.0" no es numéricoPor lo general, la validación de números se realiza con expresiones regulares. Este código determinará si algo es numérico y también buscará variables indefinidas para no generar advertencias:
sub is_integer { defined $_[0] && $_[0] =~ /^[+-]?\d+$/; } sub is_float { defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/; }
Aquí hay material de lectura que debería consultar.
fuente
\d*\.?\d+
parte introduce un riesgo de ReDoS . Recomiendo/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?$/
o/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?(?:(?<=[\d.])e[+-]?\d+)?$/i
al efecto de incluir la notación científica ( explicación y ejemplos ) en su lugar. Esto utiliza una búsqueda anticipada negativa duplicada para evitar que las cadenas como.
y.e0
pasen como números. También utiliza una mirada hacia atrás positiva para garantizar quee
sigue un número.No es perfecto, pero puedes usar una expresión regular:
sub isnumber { shift =~ /^-?\d+\.?\d*$/; }
fuente
No creo que haya nada incorporado para hacerlo. Para obtener más información de lo que nunca quiso ver sobre el tema, consulte Perlmonks sobre detección de números
fuente
Se puede encontrar una expresión regular un poco más robusta en Regexp :: Common .
Parece que quiere 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 silenciosamente a 0, que es probablemente lo que deseaba de todos modos.
fuente
rexep no 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; }
fuente
Prueba esto:
If (($x !~ /\D/) && ($x ne "")) { ... }
fuente
Aunque encontré esto interesante
if ( $value + 0 eq $value) { # A number push @args, $value; } else { # A string push @args, "'$value'"; }
fuente
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
-w
, tuve que combinar la idea de comparar el resultado de "valor más cero" con el valor original con elno warnings
enfoque basado en @ysth:do { no warnings "numeric"; if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; } }
fuente
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?
fuente
if (definido $ x && $ x! ~ m / \ D /) {} o $ x = 0 if! $ x; si ($ x! ~ m / \ D /) {}
Esta es una ligera variación de la respuesta de Veekay, pero déjeme explicar mi razonamiento para el cambio.
La realización de una expresión regular en un valor indefinido provocará un mensaje de error y hará que el código salga en muchos, si no en la mayoría de los entornos. Probar si el valor está definido o establecer un caso predeterminado como hice en el ejemplo alternativo antes de ejecutar la expresión guardará, como mínimo, su registro de errores.
fuente