Użyj, Scalar::Util::looks_like_number()
która używa funkcji look_like_number () wewnętrznego API Perl C, która jest prawdopodobnie najbardziej wydajnym sposobem na zrobienie tego. Zauważ, że ciągi „inf” i „nieskończoność” są traktowane jako liczby.
Przykład:
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";
}
Daje to wyjście:
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
Zobacz też:
perldoc perlapi
mówi nam: Sprawdź, czy zawartość SV wygląda jak liczba (lub jest liczbą). "Inf" i "Infinity" są traktowane jako liczby (więc nie będą generować ostrzeżeń nienumerycznych), nawet jeśli atof () ich nie rozumie. Trudno testowalna specyfikacja ...0x12
są uważane za liczby w tym teście.Sprawdź moduł CPAN Regexp :: Common . Myślę, że robi dokładnie to, czego potrzebujesz i obsługuje wszystkie skrajne przypadki (np. Liczby rzeczywiste, notacja naukowa itp.). na przykład
use Regexp::Common; if ($var =~ /$RE{num}{real}/) { print q{a number}; }
źródło
Pierwotne pytanie dotyczyło tego, jak stwierdzić, czy zmienna jest numeryczna, a nie czy „ma wartość liczbową”.
Istnieje kilka operatorów, które mają oddzielne tryby działania dla operandów numerycznych i łańcuchowych, gdzie „numeryczny” oznacza wszystko, co pierwotnie było liczbą lub było kiedykolwiek użyte w kontekście numerycznym (np.
$x = "123"; 0+$x
Przed dodaniem$x
jest ciągiem, a następnie jest uważany za numeryczny).Można to stwierdzić na przykład:
if ( length( do { no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
Jeśli funkcja bitowa jest włączona, to tworzy
&
tylko operator numeryczny i dodaje oddzielny&.
operator ciągu , musisz ją wyłączyć:if ( length( do { no if $] >= 5.022, "feature", "bitwise"; no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
(bitowe jest dostępne w Perlu 5.022 i nowszych i domyślnie włączone, jeśli Ty
use 5.028;
lub powyżej).źródło
sub numeric { $obj = shift; no warnings "numeric"; return eval('length($obj & "")'); }
my $obj = shift;
. Dlaczego eval?my $obj = shift
oczywiście, po prostu nie przeniosłem go poprawnie z mojego kodu do komentarza, trochę go zredagowałem. Jednaksub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }
powoduje ten sam błąd. Oczywiście posiadanie tajnej zmiennej globalnej wyjaśniłoby zachowanie, dokładnie tego bym się spodziewał w tym przypadku, ale niestety nie jest to takie proste. Ponadto zostałby złapany przezstrict
&warnings
. Wypróbowałem eval w dość desperackiej próbie pozbycia się błędu i zadziałało. Bez głębszego rozumowania, po prostu próba i błąd.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
. Jeśli umieścisz eval ('') wokół długości, ostatni wydruk da 0, tak jak powinien. Domyśl.Zwykle walidacja liczb odbywa się za pomocą wyrażeń regularnych. Ten kod określi, czy coś jest numeryczne, a także sprawdzi, czy nie ma niezdefiniowanych zmiennych, aby nie rzucać ostrzeżeń:
sub is_integer { defined $_[0] && $_[0] =~ /^[+-]?\d+$/; } sub is_float { defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/; }
Oto kilka materiałów do czytania, którym powinieneś się przyjrzeć.
źródło
\d*\.?\d+
Część wprowadza REDOS ryzyko. Zamiast tego zalecam/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?$/
lub/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?(?:(?<=[\d.])e[+-]?\d+)?$/i
dołączam notację naukową ( wyjaśnienie i przykłady ). Używa to podwójnego ujemnego wyprzedzenia, aby zapobiec przekazywaniu ciągów takich jak.
i.e0
jako liczb. Używa również pozytywnego lookbehind, aby upewnić się, żee
następuje liczba.Prosty (a może uproszczone) Odpowiedź na pytanie jest treść
$x
numeryczne jest następujący:if ($x eq $x+0) { .... }
Wykonuje tekstowe porównanie oryginału
$x
z$x
przekonwertowaną na wartość liczbową.źródło
$x eq (($x+0)."")
jednak gorszym problemem jest to, że w tej funkcji wartość „1.0” nie jest numerycznaNiezbyt idealne, ale możesz użyć wyrażenia regularnego:
sub isnumber { shift =~ /^-?\d+\.?\d*$/; }
źródło
Nie wierzę, że jest coś wbudowanego, aby to zrobić. Więcej informacji na ten temat można znaleźć w artykule Perlmonks on Detecting Numeric
źródło
Nieco bardziej solidne wyrażenie regularne można znaleźć w Regexp :: Common .
Wygląda na to, że chcesz wiedzieć, czy Perl uważa, że zmienna jest numeryczna. Oto funkcja, która przechwytuje to ostrzeżenie:
sub is_number{ my $n = shift; my $ret = 1; $SIG{"__WARN__"} = sub {$ret = 0}; eval { my $x = $n + 1 }; return $ret }
Inną opcją jest lokalne wyłączenie ostrzeżenia:
{ no warnings "numeric"; # Ignore "isn't numeric" warning ... # Use a variable that might not be numeric }
Zwróć uwagę, że zmienne nienumeryczne zostaną po cichu przekonwertowane na 0, co i tak prawdopodobnie jest tym, czego chciałeś.
źródło
rexep nie jest doskonały ... to jest:
use Try::Tiny; sub is_numeric { my ($x) = @_; my $numeric = 1; try { use warnings FATAL => qw/numeric/; 0 + $x; } catch { $numeric = 0; }; return $numeric; }
źródło
Spróbuj tego:
If (($x !~ /\D/) && ($x ne "")) { ... }
źródło
Jednak wydało mi się to interesujące
if ( $value + 0 eq $value) { # A number push @args, $value; } else { # A string push @args, "'$value'"; }
źródło
Osobiście uważam, że najlepszym rozwiązaniem jest poleganie na wewnętrznym kontekście Perla, aby rozwiązanie było kuloodporne. Dobre wyrażenie regularne może pasować do wszystkich prawidłowych wartości liczbowych i żadnej z wartości nienumerycznych (lub odwrotnie), ale ponieważ istnieje sposób na zastosowanie tej samej logiki, której używa interpreter, bezpieczniej jest polegać na tym bezpośrednio.
Ponieważ zwykle uruchamiam moje skrypty
-w
, musiałem połączyć pomysł porównania wyniku „wartość plus zero” z oryginalną wartością zno warnings
podejściem opartym na @ysth:do { no warnings "numeric"; if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; } }
źródło
Możesz użyć wyrażeń regularnych, aby określić, czy $ foo jest liczbą (czy nie).
Spójrz tutaj: Jak określić, czy skalar jest liczbą
źródło
if (zdefiniowane $ x && $ x! ~ m / \ D /) {} lub $ x = 0 jeśli! $ x; if ($ x! ~ m / \ D /) {}
To niewielka odmiana odpowiedzi Veekaya, ale pozwól mi wyjaśnić moje uzasadnienie zmiany.
Wykonanie wyrażenia regularnego na niezdefiniowanej wartości spowoduje wyrzucenie błędu i spowoduje zamknięcie kodu w wielu, jeśli nie w większości środowisk. Testowanie, czy wartość jest zdefiniowana lub ustawienie przypadku domyślnego, tak jak w alternatywnym przykładzie, przed uruchomieniem wyrażenia spowoduje co najmniej zapisanie dziennika błędów.
źródło