Используйте Scalar::Util::looks_like_number()
внутреннюю функцию Perl C API look_like_number (), которая, вероятно, является наиболее эффективным способом сделать это. Обратите внимание, что строки «inf» и «infinity» рассматриваются как числа.
Пример:
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";
}
Дает такой вывод:
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
Смотрите также:
perldoc perlapi
говорит нам: проверьте, выглядит ли содержимое SV как число (или как число). «Inf» и «Infinity» обрабатываются как числа (поэтому не будут выдавать нечисловые предупреждения), даже если ваш atof () не распознает их. Едва ли проверяемая спецификация ...0x12
которые не считаются цифры в данном тесте.Ознакомьтесь с модулем CPAN Regexp :: Common . Я думаю, что он делает именно то, что вам нужно, и обрабатывает все крайние случаи (например, действительные числа, научную запись и т. Д.). например
use Regexp::Common; if ($var =~ /$RE{num}{real}/) { print q{a number}; }
источник
Первоначальный вопрос заключался в том, как определить, является ли переменная числовой, а не «имеет ли она числовое значение».
Есть несколько операторов, которые имеют отдельные режимы работы для числовых и строковых операндов, где "числовой" означает все, что изначально было числом или когда-либо использовалось в числовом контексте (например
$x = "123"; 0+$x
, перед сложением$x
это строка, а затем считается числовым).Один из способов сказать это:
if ( length( do { no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
Если включена побитовая функция, которая создает
&
только числовой оператор и добавляет отдельный строковый&.
оператор, вы должны отключить ее:if ( length( do { no if $] >= 5.022, "feature", "bitwise"; no warnings "numeric"; $x & "" } ) ) { print "$x is numeric\n"; }
(побитовое доступно в Perl 5.022 и выше и включено по умолчанию, если вы
use 5.028;
или выше.)источник
sub numeric { $obj = shift; no warnings "numeric"; return eval('length($obj & "")'); }
my $obj = shift;
. Почему именно eval?my $obj = shift
, конечно, просто не правильно перенес из кода в комментарий, немного подредактировал. Однакоsub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }
выдает ту же ошибку. Конечно, наличие скрытой глобальной переменной объяснило бы поведение, это именно то, что я ожидал в этом случае, но, к сожалению, это не так просто. Кроме того, это будет обнаруженоstrict
&warnings
. Я попробовал eval в довольно отчаянной попытке избавиться от ошибки, и это сработало. Никаких более глубоких рассуждений, только метод проб и ошибок.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
. Если вы поместите eval ('') вокруг длины, последний отпечаток даст 0, как и должно быть. Иди разбери.Обычно проверка числа выполняется с помощью регулярных выражений. Этот код определит, является ли что-то числовым, а также проверит наличие неопределенных переменных, чтобы не выдавать предупреждения:
sub is_integer { defined $_[0] && $_[0] =~ /^[+-]?\d+$/; } sub is_float { defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/; }
Вот некоторые материалы для чтения, на которые стоит обратить внимание.
источник
\d*\.?\d+
часть вводит риск ReDoS . Я рекомендую/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?$/
или/^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?(?:(?<=[\d.])e[+-]?\d+)?$/i
включаю научные обозначения (Вместо этого объяснения и примеры ). При этом используется удвоенный отрицательный просмотр вперед, чтобы также предотвратить передачу таких строк как числа.
и в.e0
виде чисел. Он также использует положительный просмотр назад, чтобы гарантировать, чтоe
число следует за ним.Простой (и, возможно, упрощенный) ответ на вопрос заключается в следующем: числовое содержание
$x
:if ($x eq $x+0) { .... }
Он выполняет текстовое сравнение оригинала
$x
с$x
преобразованным в числовое значение.источник
$x eq (($x+0)."")
однако более серьезная проблема заключается в том, что в этой функции «1.0» не является числовымНе идеально, но вы можете использовать регулярное выражение:
sub isnumber { shift =~ /^-?\d+\.?\d*$/; }
источник
Я не верю, что для этого есть что-то встроенное. Чтобы узнать больше, чем вы когда-либо хотели, см. Perlmonks по обнаружению числовых значений.
источник
Чуть более надежное регулярное выражение можно найти в Regexp :: Common .
Похоже, вы хотите знать, считает ли Perl числовую переменную. Вот функция, которая ловит это предупреждение:
sub is_number{ my $n = shift; my $ret = 1; $SIG{"__WARN__"} = sub {$ret = 0}; eval { my $x = $n + 1 }; return $ret }
Другой вариант - отключить предупреждение локально:
{ no warnings "numeric"; # Ignore "isn't numeric" warning ... # Use a variable that might not be numeric }
Обратите внимание, что нечисловые переменные будут автоматически преобразованы в 0, что, вероятно, и так вам нужно.
источник
rexep не идеален ... это:
use Try::Tiny; sub is_numeric { my ($x) = @_; my $numeric = 1; try { use warnings FATAL => qw/numeric/; 0 + $x; } catch { $numeric = 0; }; return $numeric; }
источник
Попробуй это:
If (($x !~ /\D/) && ($x ne "")) { ... }
источник
Я нашел это интересным
if ( $value + 0 eq $value) { # A number push @args, $value; } else { # A string push @args, "'$value'"; }
источник
Лично я считаю, что лучше полагаться на внутренний контекст Perl, чтобы сделать решение пуленепробиваемым. Хорошее регулярное выражение могло бы соответствовать всем действительным числовым значениям и ни одному из нечисловых (или наоборот), но, поскольку есть способ использовать ту же логику, которую использует интерпретатор, должно быть безопаснее полагаться на это напрямую.
Поскольку я обычно запускаю свои скрипты с
-w
, мне пришлось объединить идею сравнения результата «значение плюс ноль» с исходным значением сno warnings
подходом на основе @ysth:do { no warnings "numeric"; if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; } }
источник
Вы можете использовать регулярные выражения, чтобы определить, является ли $ foo числом (или нет).
Взгляните сюда: как определить, является ли скаляр числом
источник
if (определено $ x && $ x! ~ m / \ D /) {} или $ x = 0 if! $ x; если ($ x! ~ m / \ D /) {}
Это небольшой вариант ответа Викая, но позвольте мне объяснить, почему я сделал это изменение.
Выполнение регулярного выражения для неопределенного значения вызовет выброс ошибки и вызовет завершение работы кода во многих, если не в большинстве средах. Проверка того, определено ли значение или установка случая по умолчанию, как я сделал в альтернативном примере, перед запуском выражения, как минимум, сохранит ваш журнал ошибок.
источник