Чи існує простий спосіб у Perl, який дозволить мені визначити, чи є дана змінна числовою? Щось на зразок:
if (is_number($x))
{ ... }
було б ідеально. -wБезумовно, кращою є техніка, яка не видаватиме попереджень під час використання комутатора.
Чи існує простий спосіб у Perl, який дозволить мені визначити, чи є дана змінна числовою? Щось на зразок:
if (is_number($x))
{ ... }
було б ідеально. -wБезумовно, кращою є техніка, яка не видаватиме попереджень під час використання комутатора.
Відповіді:
Використання, Scalar::Util::looks_like_number()яке використовує внутрішню функцію Perl C API Look_like_number (), що є, мабуть, найефективнішим способом зробити це. Зауважте, що рядки "inf" та "нескінченність" розглядаються як числа.
#!/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
looks_like_number0x12, не вважаються даними тесту.
Перевірте модуль 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;. Чому Евал?
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, як слід. Піди розберися.
Проста (і, можливо, спрощена) відповідь на запитання полягає в тому, що зміст $xчислової є наступним:
if ($x eq $x+0) { .... }
Він робить текстове порівняння оригіналу $xз $xперетвореним у числове значення.
$x eq (($x+0)."")однак гірша проблема полягає в тому, що за цією функцією "1.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наступну кількість.
Не ідеально, але ви можете використовувати регулярний вираз:
sub isnumber
{
shift =~ /^-?\d+\.?\d*$/;
}
Я не вірю, що є щось вбудоване для цього. Більше, ніж ви коли-небудь хотіли бачити на цю тему, див. Perlmonks on Detecting Numeric
Трохи більш надійний регулярний вираз можна знайти в 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, що, мабуть, і так і хотілося.
Мені це здалося цікавим
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 числом (чи ні).
Погляньте тут: Як визначити, чи є скаляр числом?
якщо (визначено $ x && $ x! ~ m / \ D /) {} або $ x = 0 якщо! $ х; якщо ($ x! ~ м / \ D /) {}
Це невелика варіація відповіді Вікея, але дозвольте пояснити мої міркування щодо зміни.
Виконання регулярного виразу з невизначеним значенням спричинить викид помилки та змусить код вийти у багатьох, якщо не в більшості середовищах. Тестування, чи визначено значення, або встановлення типового випадку, як це робив я в альтернативному прикладі перед запуском виразу, як мінімум збереже журнал помилок.
perldoc perlapiговорять нам: Перевірте, чи зміст SV виглядає як число (чи це число). "Inf" та "Infinity" розглядаються як цифри (тому не видаватимуть нечислове попередження), навіть якщо ваш atof () їх не перебирає. Навряд чи можна перевірити специфікацію ...