2014-06-23 39 views
4

我偶然发现了一些奇怪的Perl字符串解析。这里有一个例子:用双冒号在Perl中进行奇数字符串解析

$word = "hello"; 
$test1 = "colon:values::$word:test"; 
$test2 = "colon:values::$word::test"; 

// test1 prints: "colon:values::hello:test" 
// test2 prints: "colon:values::" 

所以,如果Perl的看到两个冒号在一个字符串变量后,它会(我认为)想你想使用包名。我想它试图加载“Hello :: test”并且找不到任何东西 - 因此提前终止了字符串。

这是正常的吗?我觉得它很违反直觉。我能够逃脱第一个冒号像这样来解决它:

$works = "colon:values::$word\::test"; 

这是bug还是我完全失去了一些东西明显?

+6

总是使用'​​use strict;使用警告;'。这会说你打印了未定义的变量'$ word :: test'。 – ikegami

回答

8

虽然这样的作品,需要处理的话更广泛的方式是用大括号来消除歧义的变量名:

perl -E "my $word = 'red'; say qq|colon::values::${word}::test|" 
colon::values::red::test 

这是记录在perldata

正如一些炮弹,您可以将变量名称括在 中,以避免字母数字(和下划线)出现。从以下双冒号或 撇号插值变量为一个字符串 独立的变量名称时,您 也必须这样做,因为这将作为一个整体进行其他处理 分离:

$who = "Larry"; 
print PASSWD "${who}::0:0:Superuser:/:/bin/perl\n"; 
print "We use ${who}speak when ${who}'s here.\n"; 

无大括号中,Perl会查找$whospeak$who::0$who's变量。最后两个将是$0$s变量(推测)不存在的包who

3

发生这种情况的原因是因为它试图查找$word::test作为变量名称。正如您已经正确推导的那样,包装分隔符::是名称的一部分,但它不会遵循$word的值,因为它不在此处用作符号引用(需要更多语法)。

Oesor的解决方案将解决您的问题 - 解决此类问题的一般方法是使用${identifier}语法。基本上可以在任何时候将变量插入到字符串中使用,并且需要使用有效的标识符字符或相关符号(即::)。

+0

或以前版本的::,\' – ysth

+0

是的,它吸引了很多人。 –

1

Perl使用名称空间作为变量名称,当Perl看到::'时,它使用Perl,它假定以前是包(即名称空间)名称。它类似于此错误

use strict; 
use warnings; # You're using these? Aren't you? 

my $foo = "bar" 
print "The magic word is $foo_for_you\n"; 

由于下划线是变量名的有效字符,Perl中假定你想要的变量$foo_for_you_for_you附加价值不$foo。那么,你会认为这是一个错误功能?它是从这个有什么区别:

print "The magic word is $foobar\n"; # Whoops! my variable is $foo. 

来解决这个问题是要绝对清楚地表明$foo的方式是你的变量:

print "The magic word is " . $foo . "_for_you\n"; 
printf "The magic word is %s_for_you\n", $foo; 
print "The magic word is ${foo}_for_you\n"; 

,如果你有同样的问题$foo::for::you(或$foo'for'you)在这种情况下,Perl正在名称空间foo::for中寻找名为$you的变量。你可以想像,你可以用类似的解决方案:

print "The magic word is " . $foo . "::for::you\n"; 
printf "The magic word is %d::for::you\n", $foo; 
print "The magic word is ${foo}::for::you\n"; 

命名空间用来帮助保持Perl模块变量在你的程序修改变量。想象一下,在一个Perl包中调用一个函数,并突然发现你的程序中使用的变量发生了变化。

看看File::Find,你可以看到变量与连接到他们($File::Find::name$File::Find::dir是两个例子)包命名空间。