Как мне узнать, имеет ли переменная числовое значение в Perl?

Есть ли в Perl простой способ, который позволит мне определить, является ли данная переменная числовой? Что-то вроде:

if (is_number($x))
{ ... }

было бы идеально. Техника, которая не будет выдавать предупреждения при использовании -wпереключателя, безусловно, предпочтительнее.

15.08.2008 19:43:15
14 ОТВЕТОВ
РЕШЕНИЕ

Используйте, Scalar::Util::looks_like_number()который использует внутреннюю функцию Perl C API look_like_number (), что, вероятно, является наиболее эффективным способом сделать это. Обратите внимание, что строки «inf» и «infinity» обрабатываются как числа.

Пример:

#!/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";
}

Дает этот вывод:

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

Смотрите также:

126
26.11.2018 14:04:01
И, как обычно с perl docs, найти фактическое определение того, что делает функция, довольно сложно. Следуя по следу, perldoc perlapiмы узнаем: проверить, выглядит ли содержимое SV как число (или число). «Inf» и «Infinity» обрабатываются как числа (поэтому не будут выдавать нечисловое предупреждение), даже если ваш atof () их не подставляет. Едва ли поддающаяся проверке спецификация ...
Day 4.10.2010 14:07:44
С описанием в Scalar :: Util все в порядке, look_like_number сообщает вам, является ли ваш ввод чем-то, что Perl будет рассматривать как число, что не обязательно является лучшим ответом на этот вопрос. Упоминание atof не имеет значения, atof не является частью CORE :: или POSIX (вы должны смотреть на strtod, который включает atof и / is / part в POSIX) и предполагая, что то, что Perl считает числом, является допустимым числовым вводом к функциям C, очевидно, очень неправильно.
MkV 18.10.2012 08:15:57
очень хорошая функция :) для неопределенных и нечисловых строк возвращает 0, для числовых строк возвращает 1, для целых возвращает 4352 и для чисел с плавающей запятой возвращает 8704 :) обычно> 0 обнаруживается число. Я проверил это под Linux.
Znik 14.05.2015 13:49:03
Мне нравится эта функция в целом, но рассмотрим большие целые. 1000000 - это множество нулей, за которыми нужно следить, прося ошибки, но 1,000,000 рассматривается как массив из трех элементов, поэтому Perl принимает 1_000_000, но look_like_number () говорит нет. Расстраивает меня.
Dave Jacoby 7.07.2015 16:19:00
Примечание: шестнадцатеричные строки, подобные 0x12, не считаются числами в этом тесте.
Adam Katz 10.10.2016 19:41:10

Не идеально, но вы можете использовать регулярное выражение:

sub isnumber 
{
    shift =~ /^-?\d+\.?\d*$/;
}
3
15.08.2008 19:49:44
Та же проблема, что и в ответе andrewrk: пропускает много даже простых случаев, например, «.7»
Aconcagua 27.03.2015 09:03:45

Обычно проверка номера выполняется с помощью регулярных выражений. Этот код будет определять, является ли что-то числовым, а также проверять неопределенные переменные, чтобы не выдавать предупреждения:

sub is_integer {
   defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}

sub is_float {
   defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
}

Вот некоторые материалы для чтения, на которые вы должны посмотреть.

8
15.08.2008 20:07:19
Я думаю, что это немного отвлекает, особенно когда спрашивающий сказал / простой /. Многие случаи, включая научные записи, вряд ли просты. Если бы не использовать это для модуля, я бы не стал беспокоиться о таких деталях. Иногда простота лучше. Не кладите шоколадный сироп в корову, чтобы сделать шоколадное молоко!
osirisgothra 2.11.2014 08:30:22
«.7» - это, вероятно, один из самых простых случаев, который до сих пор пропущен ... лучше попробуйте /^[+-]?\d*\.?\d+$/ для float. Мой вариант, учитывая научную нотацию, тоже: /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/
Aconcagua 27.03.2015 09:02:21
\d*\.?\d+Часть представляет Redos риск. Я рекомендую /^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?$/или /^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?(?:(?<=[\d.])e[+-]?\d+)?$/iвключить научную запись ( объяснение и примеры ). При этом используется двойное отрицательное предвосхищение, чтобы также не передавать строки типа .и .e0как числа. Он также использует положительный взгляд сзади, чтобы обеспечить eследующее число.
Adam Katz 8.09.2016 06:43:45

Я не верю, что для этого есть что-то встроенное. Больше, чем вы когда-либо хотели увидеть по этому вопросу, смотрите Perlmonks по обнаружению чисел.

3
15.08.2008 20:44:02

Несколько более надежное регулярное выражение можно найти в 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, что, вероятно, в любом случае вам и нужно.

2
21.10.2009 10:32:08

Проверьте модуль CPAN Regexp :: Common . Я думаю, что он делает именно то, что вам нужно, и обрабатывает все крайние случаи (например, действительные числа, научные записи и т. Д.). например

use Regexp::Common;
if ($var =~ /$RE{num}{real}/) { print q{a number}; }
23
21.10.2009 10:31:35

Первоначальный вопрос заключался в том, как определить, является ли переменная числовой, а не «имеет ли она числовое значение».

Есть несколько операторов, которые имеют отдельные режимы работы для числовых и строковых операндов, где «числовой» означает все, что изначально было числом или когда-либо использовалось в числовом контексте (например, в $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;или выше.)

22
4.09.2019 17:43:04
Отлично, спасибо! Это именно то, что я искал.
Juan A. Navarro 1.05.2012 17:09:20
Если я упаковываю вашу подпрограмму в подпрограмму, я получаю странное поведение в том, что она правильно определяет нечисловые значения, пока не опробую первое числовое значение, которое также правильно определено как истинное, но затем все остальное оттуда тоже верно. Когда я помещаю eval вокруг части length (...), она работает все время. Есть идеи, чего мне не хватало? sub numeric { $obj = shift; no warnings "numeric"; return eval('length($obj & "")'); }
yogibimbi 24.04.2013 15:29:20
@yogibimbi: вы каждый раз используете одну и ту же переменную $ obj; попробуй my $obj = shift;. Почему Eval?
ysth 24.04.2013 16:54:59
ой, мой плохой, я использовал my $obj = shift, конечно, просто неправильно перенес это из моего кода в комментарий, я немного его отредактировал. Однако sub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }выдает ту же ошибку. Конечно, наличие скрытой глобальной переменной могло бы объяснить поведение, это именно то, чего я ожидал бы в этом случае, но, к сожалению, не все так просто. Кроме того, это будет поймано strict& warnings. Я попробовал eval в довольно отчаянной попытке избавиться от ошибки, и это сработало. Нет более глубоких рассуждений, просто метод проб и ошибок.
yogibimbi 25.04.2013 18:47:29
Проверьте это: 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, как и должно быть. Пойди разберись.
yogibimbi 25.04.2013 18:59:13

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;
}
2
10.12.2010 18:58:12

Простой (и , возможно , упрощенно) ответ на вопрос , является содержание $xчислового заключается в следующем:

if ($x  eq  $x+0) { .... }

Это делает текстовое сравнение оригинала $xс $xпреобразованным в числовое значение.

9
17.10.2012 15:18:19
Это будет выдавать предупреждения, если вы используете «-w» или «использовать предупреждения;».
Derek Park 26.10.2012 15:02:57
Предупреждения могут быть удалены, $x eq (($x+0)."")однако хуже проблема в том, что под этой функцией «1.0» не является числовым
Eponymous 7.01.2015 16:10:57
достаточно протестировать $ x + 0 ne ''. когда вы наберете 0001, то правильный номер будет проверен как не номер. то же самое происходит, когда вы будете тестировать текстовое значение «.05».
Znik 14.05.2015 13:52:45

Попробуй это:

If (($x !~ /\D/) && ($x ne "")) { ... }
1
31.05.2013 16:27:30

if (определено $ x && $ x! ~ m / \ D /) {} или $ x = 0 if! $ Х; if ($ x! ~ m / \ D /) {}

Это небольшой разброс в ответе Veekay, но позвольте мне объяснить мои аргументы в пользу этих изменений.

Выполнение регулярного выражения для неопределенного значения приведет к появлению ошибки и к выходу кода во многих, если не в большинстве сред. Проверка, определено ли значение или установка регистра по умолчанию, как я делал в альтернативном примере, перед выполнением выражения, как минимум, сохранит ваш журнал ошибок.

-1
21.09.2013 16:14:58

Я нашел это интересным, хотя

if ( $value + 0 eq $value) {
    # A number
    push @args, $value;
} else {
    # A string
    push @args, "'$value'";
}
1
1.10.2015 14:20:31
Вы должны объяснить лучше, вы говорите, что вы находите это интересным, но отвечает ли он операционным требованиям? Попытайтесь объяснить, почему ваш ответ является решением для
Kumar Saurabh 1.10.2015 14:25:26
Например, мой $ value равен 1, $ value + 0 остается прежним 1. Сравнение с $ value 1 равно 1. Если $ value является строкой, скажем «swadhi», то $ value + 0 становится ascii значением строки «swadhi» + 0 = какой-то другой номер.
Swadhikar C 1.10.2015 15:02:00

Лично я считаю, что для этого нужно полагаться на внутренний контекст Perl, чтобы сделать решение пуленепробиваемым. Хорошее регулярное выражение может соответствовать всем действительным числовым значениям и ни одному из нечисловых (или наоборот), но, поскольку существует способ использовать ту же логику, которую использует интерпретатор, она должна быть более безопасной, чтобы полагаться на нее напрямую.

Поскольку я склонен запускать свои сценарии -w, мне пришлось объединить идею сравнения результата «значение плюс ноль» с исходным значением с no warningsоснованным подходом @ysth:

do { 
    no warnings "numeric";
    if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; }
}
0
31.12.2015 13:47:24

Вы можете использовать регулярные выражения, чтобы определить, является ли $ foo числом (или нет).

Посмотрите здесь: Как определить, является ли скаляр числом

0
26.02.2016 16:55:43