特定の変数が数値であるかどうかを判断できるPerlの簡単な方法はありますか?次のようなもの:
if (is_number($x))
{ ... }
理想的です。-w
スイッチが使用されているときに警告をスローしない手法が確かに推奨されます。
回答:
Scalar::Util::looks_like_number()
内部PerlC APIのlooks_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
looks_like_number
0x12
は、このテストでは数値とは見なされません。
CPANモジュールRegexp :: Commonを確認してください。必要なことを正確に実行し、すべてのエッジケース(実数、科学的記数法など)を処理すると思います。例えば
use Regexp::Common;
if ($var =~ /$RE{num}{real}/) { print q{a number}; }
元々の質問は、変数が「数値を持っている」かどうかではなく、変数が数値であるかどうかをどのように判断するかでした。
数値オペランドと文字列オペランドに別々の操作モードを持つ演算子がいくつかあります。「数値」とは、元々数値であったか、数値コンテキストで使用されたことがあるものを意味します(たとえば$x = "123"; 0+$x
、加算前は$x
文字列であり、その後は文字列です。数値と見なされます)。
伝える1つの方法はこれです:
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";
}
(bitwiseは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
次の数値を確認します。
私はそれをするために何も組み込まれているとは思わない。このテーマについてこれまでに見たかった以上のことについては、数値の検出に関する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に変換されることに注意してください。これは、おそらくとにかく必要なものです。
私はこれが面白いと思いました
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(defined $ x && $ x!〜m / \ D /){}または$ x = 0 if!$ x; if($ x!〜m / \ D /){}
これはVeekayの答えのわずかなバリエーションですが、変更の理由を説明させてください。
未定義の値に対して正規表現を実行すると、エラースピューが発生し、ほとんどの環境ではないにしても、多くの環境でコードが終了します。式を実行する前に、値が定義されているかどうかをテストするか、別の例で行ったようにデフォルトのケースを設定すると、少なくともエラーログが保存されます。
perldoc perlapi
がわかります。SVの内容が数字のように見える(または数字である)かどうかをテストします。「Inf」と「Infinity」は、atof()がそれらを取得しなくても、数値として扱われます(したがって、数値以外の警告は発行されません)。ほとんどテスト可能なスペック...