此代码:
#!/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 'use Scalar::Util; print "$Scalar::Util::VERSION\n"'
- > 1.19
perl -v
- >这是为darwin-thread-multi-2level构建的perl,v5.10.0(有2个已注册的补丁,有关详细信息,请参阅perl -V)
答案 0 :(得分:4)
我在你的程序中做了一些修改:
#! /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);
}
}
}
我的Mac运行10.8.6,我使用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
然后我对你的程序做了另一个小改动。我不是简单地使用$1
,而是设置my $test = $1
,然后运行looks_like_number( $test )
;
完成后,我得到了这个:
Scalar version: 1.19
"123" looks like a number
"123" looks like a number
"123" looks like a number
您必须了解的一点是,$1
,$_
及其同类不仅仅是全局变量,而且始终位于main
命名空间中。这意味着如果使用$1
调用子例程,则子例程可能最终会重置该值。
您应该始终分配自己的变量(最好是my
变量),而不是依赖于特殊的Perl变量。这意味着不在$_
和while
循环中使用for
,也不在子例程中直接操作@_
。而且,当您使用正则表达式捕获时,您应该尽快将自己的变量分配给$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语句中。有趣的是,副作用仅在第一个中被捕获 - 尽管子例程正在设置字符串,并运行正则表达式。相同的代码,但执行两种不同的方式。
在$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.
有效吗?让我们在没有-d
参数的情况下尝试相同的命令:
$ perl test.pl
Version of Scalar::Util: 1.19
"123" doesn't look like a number.
"123" looks like a number.
"123" looks like a number.
如果您无法在调试器中看到它,如何追溯此问题?
答案 1 :(得分:4)
这是在Scalar :: Util 1.20中修复的错误。 (“处理Changes
文件中的重载和绑定值。”
looks_like_number
的XS版本未能正确处理神奇的论点。 Magic是允许在对变量执行某些操作时调用代码(例如获取其值)。
解决方案:
looks_like_number("$1")
创建具有正确价值的$1
的非魔法副本。1.19:
int
looks_like_number(sv)
SV *sv
PROTOTYPE: $
CODE:
#if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION <5)
if (SvPOK(sv) || SvPOKp(sv)) {
RETVAL = looks_like_number(sv);
}
else {
RETVAL = SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
}
#else
RETVAL = looks_like_number(sv);
#endif
OUTPUT:
RETVAL
1.21:
int
looks_like_number(sv)
SV *sv
PROTOTYPE: $
CODE:
SV *tempsv;
if (SvAMAGIC(sv) && (tempsv = AMG_CALLun(sv, numer))) {
sv = tempsv;
}
else if (SvMAGICAL(sv)) {
SvGETMAGIC(sv);
}
#if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION <5)
if (SvPOK(sv) || SvPOKp(sv)) {
RETVAL = looks_like_number(sv);
}
else {
RETVAL = SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
}
#else
RETVAL = looks_like_number(sv);
#endif
OUTPUT:
RETVAL
试试这个:
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
答案 2 :(得分:2)
据池上说,
您可能正在使用纯Perl版本的Scalar :: Util 可能使用正则表达式,其中包含1美元。 looks_like_number(“$ 1”)会 解决它。
谢谢!这解决了它。