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