Perl-这是一个看起来像数字的bug,还是我是一个愚蠢的人?
此代码:Perl-这是一个看起来像数字的bug,还是我是一个愚蠢的人?,perl,Perl,此代码: #!/usr/bin/perl -w use strict; use Scalar::Util qw(looks_like_number); sub what_the_fudge { my $string = "foo 123 bar"; if ($string =~ /foo (.+) bar/) { if (looks_like_number($1)) { print "$1 looks like a number\n";
#!/usr/bin/perl -w
use strict;
use Scalar::Util qw(looks_like_number);
sub what_the_fudge {
my $string = "foo 123 bar";
if ($string =~ /foo (.+) bar/) {
if (looks_like_number($1)) {
print "$1 looks like a number\n";
} else {
print "$1 doesnt look like a number\n";
}
}
}
&what_the_fudge;
&what_the_fudge;
&what_the_fudge;
显示以下内容:
123 doesnt look like a number
123 looks like a number
123 looks like a number
为什么它第一次就不能识别它是一个数字=(
这使我困惑
有关我的环境的一些信息:
操作系统:OSX 10.6.8
perl-e“使用标量::Util;打印“$Scalar::Util::VERSION\n”
-->1.19
perl-v
-->这是为darwin-thread-multi-2level构建的perl,v5.10.0(有2个注册补丁,请参阅perl-V以了解更多细节)据ikegami说
您可能正在使用纯Perl版本的Scalar::Util,它 可能使用的是一个正则表达式,它的值为1美元。看起来像数字($1)会 修好它
谢谢!这解决了问题。我对您的程序做了一些修改:
#! /usr/bin/env perl
#
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
print "Scalar version: $Scalar::Util::VERSION\n";
what_the_fudge();
what_the_fudge();
what_the_fudge();
sub what_the_fudge {
my $string = "foo 123 bar";
if ($string =~ /foo (.+) bar/) {
if ( looks_like_number $1 ) {
print qq("$1" looks like a number\n);
} else {
print qq("$1" doesn't look like a number\n);
}
}
}
我有一个运行10.8.6的Mac,我使用Perlbrew测试5.8.9、5.10、5.12和5.18。对于前两个,我得到了以下结果:
Scalar version: 1.19
"123" doesnt look like a number
"123" looks like a number
"123" looks like a number
Scalar version: 1.22
"123" looks like a number
"123" looks like a number
"123" looks like a number
对于其他两个版本,我得到了以下结果:
Scalar version: 1.19
"123" doesnt look like a number
"123" looks like a number
"123" looks like a number
Scalar version: 1.22
"123" looks like a number
"123" looks like a number
"123" looks like a number
然后我在你的程序中做了另一个小改动。我没有简单地使用$1
,而是设置my$test=$1
,然后运行looks\u like\u number($test)
在做了这些之后,我得到了:
Scalar version: 1.19
"123" looks like a number
"123" looks like a number
"123" looks like a number
您必须了解的一点是,$1
、$\u
及其类似项不仅是全局变量,而且始终位于主
命名空间中。这意味着,如果您使用$1
调用子例程,则子例程可能最终会调用该值
您应该始终分配自己的变量(最好是my
变量)不要依赖特殊的Perl变量。这意味着不要在中使用$\uCode>,而在循环中使用和,也不要直接在子例程中操作@
。而且,当使用正则表达式捕获时,应该尽快将自己的变量分配给$1
,$2
等
顺便说一句,Scalar::Util版本1.22和1.19之间最有趣的区别是,如果存在,版本1.22将使用C编译的代码。如果没有,它将加载Scalar::Util::PP,这是Perl版本。但是,当我在Perl 5.12和5.18中使用Scalar::Util::PP
时,我仍然得到了正确的输出
送小孩
我试图修改Scalar::Util
以查看发生了什么。但是,我看到:
require List::Util; # List::Util loads the XS
Perl版本的代码被封装在一个大的Eval语句中。有趣的是,副作用只出现在第一个语句中——尽管子例程正在设置字符串并运行regex。相同的代码,但执行两种不同的方式
在$1
周围添加引号可使其行为正确:
if ( looks_like_number "$1" ) {
此外,只需将其打印出来即可使其正常工作:
print "The value is " . $1 . "\n";
if ( looks_like_number $1 ) {
或将其分配给另一个变量,但不使用该变量:
my $test = $1;
if ( looks_like_number $1 ) { works now...
让我们使用调试器,看看是否可以跟踪问题:
$ perl -d test.pl
Loading DB routines from perl5db.pl version 1.31
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(test.pl:7): print "Version of Scalar::Util: $Scalar::Util::VERSION\n";
DB<1> c
Version of Scalar::Util: 1.19
"123" looks like a number.
"123" looks like a number.
"123" looks like a number.
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
如果无法在调试器中查看该问题,您如何跟踪该问题?这是Scalar::Util 1.20中修复的一个错误。(更改文件中的“处理重载和绑定值”)
XS版本的看起来像\u number
无法正确处理神奇的参数。当对变量执行某些操作(例如获取其值)时,可以调用神奇的代码
解决方案:
- 升级到Scalar::Util 1.20或更高版本
- 删除Scalar::Util的编译组件,以强制使用纯Perl实现,而纯Perl实现不会遇到此问题
- 使用类似于数字($1)的
创建具有正确值的$1
的非魔法副本
1.19:
我还没试过,但你应该
Version of Scalar::Util: 1.19
doesnt look like a number
looks like a number
doesnt look like a number
不能复制,我三次都得到正确的结果。你可以考虑重新命名你的子的名字。因此,多个CNR(不能复制)报告——你使用的是哪种版本的Perl,你使用哪个平台?请显示“代码> Perl -e”的输出:使用标量::UTIL;$$标量::UTIL::Vertual\n“
您可能使用的是纯Perl版本的Scalar::Util,它可能使用一个正则表达式,这个正则表达式将$1
看起来像一个数字($1”)
将修复它。正如@pilcrow指出的,我对原因的猜测似乎是错误的。我的新猜测是,该版本的Perl中存在一个错误,导致$1
的魔力无法被调用。解决方案是一样的,因为$1
的字符串化(看起来像一个数字($1”)
)调用它的魔力。它不是纯Perl版本。我在使用Perlbrew的机器上也有同样的问题,我可以验证纯Perl版本没有被加载。使用调试器也解决了这个问题。“[a]子例程[使用$1调用]可能最终会占用[$1]”嗯,是的,但只在sub本身内部。因为至少5.8.8,$1
是自动且有帮助的动态范围(呃,动态本地化),因此该子例程的调用方在返回时不会注意到对$1
的任何更改。@pilcrow奇怪的是,相同的代码执行了三次,但第一次返回的结果不同。@David W.,请参阅我的答案。使用Devel::Peek的Dump
并查看调用前后的PV
ike_number
。您将看到它没有更改,它应该由mg_get
更新。由于字符串concat,它会在以后工作
what_the_fudge("foo 123 bar");
what_the_fudge("foo baz bar");
what_the_fudge("foo 123 bar");
sub what_the_fudge {
my $string = shift;
Version of Scalar::Util: 1.19
doesnt look like a number
looks like a number
doesnt look like a number