Perl的隐藏功能?


143

您实际上已能够使用Perl中哪些真正有用但深奥的语言功能来完成有用的工作?

指导原则:

  • 尝试将答案限制在Perl核心而非CPAN上
  • 请举一个例子和简短描述

在其他语言的“隐藏功能”中也可以找到“隐藏功能”:

(这些都是Corion的回答

  • C
    • 达夫的装置
    • 便携性和标准性
  • C#
    • 空格分隔列表和字符串的引号
    • 别名空间
  • 爪哇
    • 静电诱剂
  • 的JavaScript
    • 职能是一等公民
    • 块范围和关闭
    • 通过变量间接调用方法和访问器
  • 红宝石
    • 通过代码定义方法
  • 的PHP
    • 无处不在的在线文档
    • 魔术方法
    • 符号参考
  • 蟒蛇
    • 一线交换
    • 能够用自己的功能替换甚至核心功能

其他隐藏功能:

运营商:

引用构造:

语法和名称:

模块,编译指示和命令行选项:

变量:

循环和流量控制:

常用表达:

其他特性:

其他技巧和元答案:


也可以看看:


这些功能大多数都在日常使用中,某些功能出现在大多数Perl脚本中,并且大多数列在“其他”下的内容仍源于其他语言,称这些“隐藏”改变了问题的意图。
reinierpost,2010年

Answers:


54

触发器运算符在循环遍历文件句柄返回的记录(通常为行)时不使用标志变量时非常有用:

while(<$fh>)
{
  next if 1..1; # skip first record
  ...
}

运行perldoc perlop并搜索“触发器”以获取更多信息和示例。


实际上,这取自Awk,您可以通过编写pattern1,pattern2在两个模式之间进行触发器
Bruno De Fraine

15
需要说明的是,“隐藏”方面是,如果标量“ ..”的任何一个操作数都是常量,则将其值与输入行号($。)进行隐式比较
Michael Carman,

47

Perl中有许多非显而易见的功能。

例如,您知道标记后可以有空格吗?

 $ perl -wle 'my $x = 3; print $ x'
 3

还是如果您使用符号引用,可以给subs数字名称?

$ perl -lwe '*4 = sub { print "yes" }; 4->()' 
yes

还有一个“ bool”准运算符,它为真表达式返回1,为假返回空字符串:

$ perl -wle 'print !!4'
1
$ perl -wle 'print !!"0 but true"'
1
$ perl -wle 'print !!0'
(empty line)

其他有趣的东西:use overload可以重载字符串文字和数字(例如,使它们成为BigInts或其他类型)。

这些东西中的许多实际上是在某个地方记录的,或者是从记录的特征上逻辑地遵循的,但是尽管如此,某些东西还是不太为人所知。

更新:另一个不错的。q{...}下面提到了引用结构,但是您知道您可以将字母用作分隔符吗?

$ perl -Mstrict  -wle 'print q bJet another perl hacker.b'
Jet another perl hacker.

同样,您可以编写正则表达式:

m xabcx
# same as m/abc/

2
“你知道在印记后面可以有空格吗?” 我完全发疯了。哇。
亚里斯多德·帕加兹

1
凉!!! $ undef_var不会创建警告。
Axeman

4
我认为您使用字母分隔字符串的示例应该是“ 只是另一个perl黑客”,而不是“ Jet另一个perl黑客” = P
Chris Lutz

最糟糕的是,您也可以使用其他东西作为分隔符。甚至连括号。以下是有效的:s} regex} replacement} xsmg; q]字符串文字];
瑞安·汤普森

46

通过魔术ARGV添加对压缩文件的支持:

s{ 
    ^            # make sure to get whole filename
    ( 
      [^'] +     # at least one non-quote
      \.         # extension dot
      (?:        # now either suffix
          gz
        | Z 
       )
    )
    \z           # through the end
}{gzcat '$1' |}xs for @ARGV;

(用外壳元字符处理文件名时,必须在$ _前后加上引号)

现在,该<>功能将解压缩@ARGV以“ .gz”或“ .Z”结尾的所有文件:

while (<>) {
    print;
}

2
我认为您无需|在替换中转义。
克里斯·卢茨

我盯着这个,我不知道它是如何工作的。在什么时候将其zcat |解析为传递指令?
以太

1
@Ether =>检测管道是打开两个参数的功能,钻石操作员在打开每个文件时都会使用它@ARGV
Eric Strom 2010年

40

Perl中我最喜欢的功能之一是使用布尔||运算符在一组选项之间进行选择。

 $x = $a || $b;

 # $x = $a, if $a is true.
 # $x = $b, otherwise

这意味着可以写:

 $x = $a || $b || $c || 0;

采取从第一个真正的价值$a$b$c,或默认的0否则。

在Perl 5.10中,还有一个//运算符,如果定义了该运算符,则返回左侧,否则返回右侧。下面选择第一限定值从$a$b$c,或0以其他方式:

$ x = $ a // $ b // $ c // 0;

这些也可以与其简写形式一起使用,这对于提供默认值非常有用:

$ x || = 0; #如果$ x为假,则其值为0。

$ x // = 0; #如果$ x未定义,则其值为零。

谢里奥

保罗


4
这是一个非常常见的习惯用法,几乎没有资格被视为“隐藏”功能。
迈克尔·卡曼

3
羞愧漂亮的打印机认为// //是评论:)
约翰·弗格森

2
问题,是否有使用这些新运算符的“使用功能”,或者默认启用它们?我仍在学习Perl 5.10的功能。
JJ

6
//默认情况下位于其中,无需任何特殊调整。您也可以使用dor-patch将其反向移植到5.8.x中。请参阅任何CPAN镜像上的authors / id / H / HM / HMBRAND /目录。FreeBSD 6.x及更高版本在其perl软件包中为您完成了此任务。
dland

2
当||时 或//与do {}结合使用,您可以封装更复杂的赋值,即$ x = $ a || 做{我的$ z; 3或4行推导;$ z};
RET

39

运算符++和一元运算符-不仅适用于数字,而且适用于字符串。

my $_ = "a"
print -$_

打印-a

print ++$_

打印b

$_ = 'z'
print ++$_

打印aa


3
引用perlvar的话:“自动减量运算符不是神奇的。” 因此--不适用于字符串。
莫里茨

“ aa”似乎不是跟随“ z”的自然元素。我期望下一个最高的ascii值是“ {”。
以太

4
不要问程序员“ z”之后是什么。问一个人。此功能非常适合为长列表中的项目编号。
巴里·布朗

17
当我是Perl的新手时,我用一个准确的z to aa行为自己实现了此功能,然后向同事笑了起来,然后我和我笑着说:“让我给你看点东西”。我哭了一下,但学到了一些东西。
巴拿马杯

2
@Ether-如果需要,请使用数字并将其自动转换为ASCII ord()。或者,编写一个小类并重载运算符为您执行此操作。
克里斯·卢兹

36

由于Perl几乎具有其他列表中的所有“深奥”部分,因此我将告诉您Perl无法做到的一件事:

Perl不能做的一件事就是在您的代码中包含裸露的任意URL,因为 //运算符用于正则表达式。

万一Perl提供了哪些功能,以防您不明白,下面列出了一些可能并不完全显而易见的条目:

达夫设备 - 在Perl

可移植性和标准性 - 使用Perl的计算机可能比使用C编译器的计算机更多

一个文件/路径操作类 - 文件::查找上更操作系统比净做作品

对于空格分隔列表行情 和字符串 - Perl的允许您选择适合您的列表和字符串分隔符几乎任意引号

可别名的名称空间-Perl通过全局分配具有这些名称空间

*My::Namespace:: = \%Your::Namespace

静态初始化程序 -Perl几乎可以在编译和对象实例化的每个阶段运行代码,从BEGIN(代码解析)到CHECK(代码解析后)到import(在模块导入时)到new(对象实例化)到DESTROY(对象销毁)再到END(程序退出)

功能是一流的公民 -就像在Perl中一样

块作用域和闭包 -Perl兼有

通过变量间接调用方法和访问器 -Perl也这样做:

my $method = 'foo';
my $obj = My::Class->new();
$obj->$method( 'baz' ); # calls $obj->foo( 'baz' )

通过定义代码中的方法 - Perl的允许过

*foo = sub { print "Hello world" };

普适在线文档 - Perl文档处于联机状态,很可能你的系统太

每当您调用“不存在”的函数时就会调用魔术方法 -Perl在AUTOLOAD函数中实现该方法

符号引用 -建议您远离这些符号他们会吃掉你的孩子。但是,当然,Perl允许您为孩子提供嗜血的恶魔。

一线交换 -Perl允许列表分配

能够用自己的功能替换甚至核心功能

use subs 'unlink'; 
sub unlink { print 'No.' }

要么

BEGIN{
    *CORE::GLOBAL::unlink = sub {print 'no'}
};

unlink($_) for @ARGV

与其他语言相比,我更喜欢Perl的文档,但我仍然认为对于Regexes和引用,可以将其合理化很多。例如,正则表达式的最佳入门书不是Perlre,而是Perlop
John Ferguson,

9
“ Perl不能做的一件事是在代码中包含裸露的任意URL,因为//运算符用于正则表达式。” -这完全是胡说八道。

感谢您的见解。我已经研究了一些在Perl代码中使用裸http:// ... URL而不使用源过滤器的方法,但是没有找到方法。也许您可以证明这是可行的?//用于Perl 5.8.x及更高版本中的正则表达式。在5.10中,它已重新定义或赋值。
Corion”

8
您为什么/在代码中想要裸URL?我想不出一个例子。
被抛弃

18
没有人会想要的,这只是Java模因。“ foo.com ”是标签http :,然后是注释中的“ foo.com”。有些人觉得这很有趣,因为...他们很愚蠢。
jrockway

35

自我生存。AFAIK 没有其他语言可以使用


我不知道Python等人不支持这一点。
skiphoppy

@davidnicol:真的吗?你能提供一个链接吗?我在Google上的快速搜索未返回任何内容。对于那些不知道ECMAscript是Javascript正确名称的人。en.wikipedia.org/wiki/ECMAScript
JJ

1
而且有一个模块可以禁止自动生存
Alexandr Ciornii 09年

1
@Gregg Lind-考虑到Python每次您首次给变量分配变量时都会自动创建变量,因此自动生存将在一个错字中产生巨大的问题。
克里斯·卢茨

3
@tchrist-a = [[x * y表示xrange(1,11)中的y,x表示xrange(1,11)中的]]
2010年

31

在Perl中引用几乎任何类型的奇怪字符串都很简单。

my $url = q{http://my.url.com/any/arbitrary/path/in/the/url.html};

实际上,Perl中的各种报价机制都非常有趣。类似Perl正则表达式的报价机制允许您报价任何内容,并指定分隔符。您几乎可以使用任何特殊字符(例如#,/)或打开/关闭字符(例如(),[]或{})。例子:

my $var  = q#some string where the pound is the final escape.#;
my $var2 = q{A more pleasant way of escaping.};
my $var3 = q(Others prefer parens as the quote mechanism.);

报价机制:

q:文字引用;唯一需要转义的字符是结束字符。qq:解释的报价;处理变量和转义字符。非常适合您需要引用的字符串:

my $var4 = qq{This "$mechanism" is broken.  Please inform "$user" at "$email" about it.};

qx:与qq相似,但是作为系统命令非交互地执行。返回从标准输出生成的所有文本。(如果操作系统支持,也可以进行重定向)也可以使用反引号(`字符)。

my $output  = qx{type "$path"};      # get just the output
my $moreout = qx{type "$path" 2>&1}; # get stuff on stderr too

qr:像qq一样解释,但随后将其编译为正则表达式。也可以在正则表达式上使用各种选项。您现在可以将正则表达式作为变量传递:

sub MyRegexCheck {
    my ($string, $regex) = @_;
    if ($string)
    {
       return ($string =~ $regex);
    }
    return; # returns 'null' or 'empty' in every context
}

my $regex = qr{http://[\w]\.com/([\w]+/)+};
@results = MyRegexCheck(q{http://myurl.com/subpath1/subpath2/}, $regex);

qw:一个非常非常有用的引用运算符。将带引号的一组用空格分隔的单词转换为列表。非常适合在单元测试中填写数据。


   my @allowed = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z { });
   my @badwords = qw(WORD1 word2 word3 word4);
   my @numbers = qw(one two three four 5 six seven); # works with numbers too
   my @list = ('string with space', qw(eight nine), "a $var"); # works in other lists
   my $arrayref = [ qw(and it works in arrays too) ]; 

只要事情变得更清晰,它们就很好用。对于qx,qq和q,我很可能使用{}运算符。使用qw的人最常见的习惯通常是()运算符,但有时您还会看到qw //。


1
我有时会使用qw“”,以便语法突出显示将正确突出显示它。
布拉德·吉尔伯特

在SlickEdit中为我工作。:)
罗伯特·P

1
@fengshaun,编辑我一般用正确突出了这些。我在某种程度上是指StackOverflow上的语法荧光笔。
布拉德·吉尔伯特

@布拉德·吉尔伯特:堆栈溢出无法(嗯,(不)分析值得
Perdly

my $moreout = qx{type "$path" 2>&1};...我不知道你能做到![TM]
dland

27

并不是真正的隐藏,但是每天很多Perl程序员都不了解CPAN。这尤其适用于那些不是全职程序员或不以Perl全职编程的人。


27

可以与在Pascal中使用“ with”的方式一样使用“ for”语句:

for ($item)
{
    s/&‎nbsp;/ /g;
    s/<.*?>/ /g;
    $_ = join(" ", split(" ", $_));
}

您可以对同一变量应用一系列s ///等操作,而不必重复变量名称。

注意:上方(&nbsp;)的不间断空格在其中隐藏了Unicode,以规避Markdown。不要复制粘贴它:)


而“ map”也有同样的技巧... map {....} $ item; 使用“ for”而不是“ map”的一个优势是,您可以使用next进行分组。
draegtun

2
此外,因为在代码进行操作之前已列出了要操作的项目,从而提高了可读性。
罗伯特·P

@RobertP:是的。话题分析器在话语中很有用。
tchrist 2010年

26

引号运算符是我最喜欢的东西之一。比较:

my @list = ('abc', 'def', 'ghi', 'jkl');

my @list = qw(abc def ghi jkl);

噪音少得多,对眼睛更容易。关于Perl的另一件非常有趣的事情是,编写SQL时确实会错过这一点,那就是结尾的逗号是合法的:

print 1, 2, 3, ;

这看起来很奇怪,但是如果您以其他方式缩进代码,则不会:

print
    results_of_foo(),
    results_of_xyzzy(),
    results_of_quux(),
    ;

在函数调用中添加其他参数并不需要您在前一行或尾随的逗号上打乱。单行更改对其周围的行没有影响。

这使得使用可变参数功能非常令人愉快。这也许是Perl最被低估的功能之一。


2
Perl语法的一个有趣的特殊情况是,以下内容是有效的:$ _ qw(东西列表){...}
短暂

1
只要不使用*?之类的特殊字符,您甚至可以滥用glob语法来引用单词。所以您可以写for (<a list of stuff>) { ... }
moritz

1
@ephemient:差不多了。这仅适用于词汇:对于我的$ x qw(abc){...}例如:对于$ _ qw(abc){print}#不输出任何内容
dland

当您可以享受perl最喜欢的默认值时,为什么还要添加额外的词汇呢?为(qw / abcd /){打印; }
fengshaun 2010年

2
@ ephemient,@ fengshaun,@ moritz,@ dland:这是在blead中 “固定”的;看到这个p5p线程
tchrist 2010年

26

解析直接粘贴到DATA块中的数据的能力。无需保存到要在程序中打开的测试文件或类似文件。例如:

my @lines = <DATA>;
for (@lines) {
    print if /bad/;
}

__DATA__
some good data
some bad data
more good data 
more good data 

在小测试中非常有用!
fengshaun 2010年

@peter mortensen您将如何使用多个块?您如何结束封锁?
Toad

@Toad:这是艾伦的答案(请参阅修订列表)。最好与该用户联系。或者,由于该用户离开了Stack Overflow,也许没有人特别关注(因此,一名真正的Perl专家可以稍后解决)。
彼得·莫滕森

3
@海:不,它并不丑陋-实际上,它与丑陋恰恰相反:它干净,苗条,简约而美丽。简而言之,它很棒,没有它的语言就是PITA。@peter mortensen,@ toad:关于如何在同一程序中具有多个数据块的一个答案是在CPAN 上使用Inline :: Files模块。
tchrist

Inline :: Files使用源过滤器实现。还有Data :: Section,它提供多个内联块并且不使用源过滤器。
Prakash K

24

新区块操作

我想说,扩展语言,创建伪块操作的能力是其中之一。

  1. 您声明一个子原型,以指示它首先接受代码引用:

    sub do_stuff_with_a_hash (&\%) {
        my ( $block_of_code, $hash_ref ) = @_;
        while ( my ( $k, $v ) = each %$hash_ref ) { 
            $block_of_code->( $k, $v );
        }
    }
  2. 然后可以像这样在体内称呼它

    use Data::Dumper;
    
    do_stuff_with_a_hash {
        local $Data::Dumper::Terse = 1;
        my ( $k, $v ) = @_;
        say qq(Hey, the key   is "$k"!);
        say sprintf qq(Hey, the value is "%v"!), Dumper( $v );
    
    } %stuff_for
    ;

Data::Dumper::Dumper是另一种半隐藏的宝石。)请注意,您不需要sub在块前面或哈希前的逗号。最终看起来很像:map { } @list

源过滤器

另外,还有源过滤器。Perl会将代码传递给您的地方,以便您可以进行操作。这和块操作几乎都不尝试在家中进行。

我使用源过滤器做了一些整洁的事情,例如,创建一种非常简单的语言来检查时间,允许使用简短的Perl单行代码进行某些决策:

perl -MLib::DB -MLib::TL -e 'run_expensive_database_delete() if $hour_of_day < AM_7';

Lib::TL 只会扫描“变量”和常量,创建它们并根据需要替换它们。

同样,源过滤器可能很杂乱,但功能强大。但是它们可能使调试器陷入混乱,甚至可能用错误的行号打印警告。我停止使用达米安的开关因为调试器将失去所有告诉我实际位置的能力。但是我发现,可以通过修改一小段代码并将它们保持在同一行上来最大程度地减少损害。

信号钩

通常这已经足够完成了,但是并不是很明显。这是一个模子处理程序,背负着旧的处理程序。

my $old_die_handler = $SIG{__DIE__};
$SIG{__DIE__}       
    = sub { say q(Hey! I'm DYIN' over here!); goto &$old_die_handler; }
    ;

这意味着每当代码中的其他模块想要消亡时,它们都会来找你(除非别人对它进行破坏性的覆盖 $SIG{__DIE__})。并且您会收到通知,告知某人某些事情是错误的。

当然END { },如果您想要做的只是清理,对于足够的事情,您可以仅使用块。

overload::constant

您可以检查包含模块的软件包中某种类型的文字。例如,如果在您的import子目录中使用此代码:

overload::constant 
    integer => sub { 
        my $lit = shift;
        return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit 
    };

这意味着调用包中的每个大于20亿的整数都将变为一个Math::BigInt对象。(请参见重载::: constant)。

分组整数文字

当我们在它。Perl允许您将大数字分成三位数的组,并且仍然从中得到一个可解析的整数。请注意2_000_000_000上面的20亿。


5
当使用$ SIG { DIE }处理程序时,强烈建议您检查$ ^ S以查看您的程序是否真的死了,或者只是抛出将要捕获的异常。通常,您不想干扰后者。
pjf

新块很有启发性!我当时在想那是语言的语义!非常感谢。
ZeroCool 2010年

源过滤器的指导性用途是pdl的NiceSlice(pdl.perl.org/?docs=NiceSlice&title=PDL::NiceSlice),因此不需要在->slice每次需要切片时都使用as作为方法。
乔尔·伯杰

24

二进制“ x”是重复运算符

print '-' x 80;     # print row of dashes

它也适用于列表:

print for (1, 4, 9) x 3; # print 149149149

这就是Perl在黑客中如此受欢迎的原因之一。perl -e'打印0x000 x 25';
JJ

4
我最喜欢的用法是为SQL INSERT语句的最后一部分生成占位符:@p =('?')x $ n; $ p = join(“,”,@p); $ sql =“插入...值($ p)”;
skiphoppy

24

污染检查。启用污点检查后,-t如果您尝试将污点数据(大致来说,来自程序外部的数据)传递给不安全的功能(打开文件,运行外部命令等),则perl将死亡(或使用发出警告)。在编写setuid脚本或CGI或脚本具有比提供数据的人员更大特权的任何内容时,这非常有帮助。

魔术转到。 goto &sub做一个优化的尾叫。

调试器。

use strictuse warnings。这些可以避免一堆错字。


1
为什么其他语言没有此功能?使用的此功能使perl Web脚本更加安全。
马修·洛克

22

根据Perl 5中"-n"and "-p"开关的实现方式,您可以编写一个看似不正确的程序,包括}{

ls |perl -lne 'print $_; }{ print "$. Files"'

在内部转换为以下代码:

LINE: while (defined($_ = <ARGV>)) {
    print $_; }{ print "$. Files";
}

@马丁·克莱顿:为什么这么称呼它?
tchrist 2010年

@tchrist-因为据说它看起来像两个人擦鼻子。在个人资料中,如果您明白我的意思。
马丁克莱顿

18

让我们从宇宙飞船Operator轻松开始。

$a = 5 <=> 7;  # $a is set to -1
$a = 7 <=> 5;  # $a is set to 1
$a = 6 <=> 6;  # $a is set to 0

1
@Leon:C / C ++不会为数字返回3值。如果内存提供String comapre函数,那是我在整个STL语言中唯一知道的3个值返回。AFAIK Python没有3返回数值比较。Java也没有特定于数字的3返回比较。
JJ

7
值得一提的是,关于-1/0/1比较运算符有什么用,因为并不是每个人都知道:您可以将它们与or-运算符链接在一起以进行主/次/等操作。排序。因此,($a->lname cmp $b->lname) || ($a->fname cmp $b->fname)按姓氏对人进行排序,但是如果两个人的姓氏相同,则将按其姓氏对其进行排序。
hobbs 2010年

@JJ Python确实具有3值比较:cmp()>>> print(cmp(5,7),cmp(6,6),cmp(7,5))(
1,0,1

18

这是一个元答案,但Perl提示档案包含可以完成的各种有趣的技巧。先前技巧的存档可以在线浏览,并且可以通过邮件列表或原子供稿进行订阅。

我最喜欢的一些技巧包括使用PAR构建可执行文件使用autodie自动引发异常以及在Perl 5.10中使用switchsmart-match构造。

披露:我是Perl Tips的作者和维护者之一,因此,我显然对他们非常重视。;)


2
它可能是目前最好的文档化语言之一,并设置了搜索文档的工具模式。该问题中的列表可能不像其他语言那样需要。
斧头侠》

1
autodie看起来非常好。
j_random_hacker

18

map-不仅是因为它使一个人的代码更具表现力,而且还因为它带给了我阅读更多有关此“功能编程”的冲动。


15

循环上的继续子句。它会在每个循环的底部执行,即使是下一个循环也是如此。

while( <> ){
  print "top of loop\n";
  chomp;

  next if /next/i;
  last if /last/i;

  print "bottom of loop\n";
}continue{
  print "continue\n";
}

15

我的投票将赞成Perl正则表达式中的(?{})和(?? {})组。第一个执行Perl代码,忽略返回值,第二个执行代码,使用返回值作为正则表达式。


perl发明了太多的regexp扩展,以至于其他程序现在经常使用pcre(与perl兼容的regex)代替原始的regex语言。
二段

读到这里的小Blurb的perldoc.perl.org/... :-D
JJ

就正则表达式而言,Perl确实(据我所知)遥遥领先。
布拉德·吉尔伯特

据我所知,这仍然是试验性的,在将来的Perls中可能无法以相同的方式工作。并不是说它没有用,而是可以在s ///命令的/ e标志中找到一个稍微更安全且可用的版本:s/(pattern)/reverse($1);/ge;#反转all patterns
克里斯·卢兹

@Chris Lutz,@ Leon Timmerman:请注意,这两个构造现在都是重新公开的。还要注意,既然我们可以对捕获组进行递归,则不再需要使用第二种来实现递归模式。@布拉德·吉尔伯特:是的,尽管PCRE在跟踪我们方面做得不错。Perl完全不受挑战的正则表达式卓越领域之一是对Unicode属性的访问。请参阅我对的unitrio分布uninamesunichars特别是uniprops请参阅我的意思的一部分。
tchrist 2010年

13
while(/\G(\b\w*\b)/g) {
     print "$1\n";
}

\ G锚点。它是热的


3
...,它指示上一场比赛结束的位置。
Dave Sherohman

1
但是您必须在标量上下文中调用正则表达式。
davidnicol

@davidnicol:上面的代码有效。您能说明您的意思吗?
JJ

13

m//运营商有一些模糊的特殊情况:

  • 如果?用作分隔符,则除非调用,否则它仅匹配一次reset
  • 如果'用作定界符,则不会插值模式。
  • 如果模式为空,则使用上一次成功匹配中的模式。

2
这些更像是隐藏的陷阱而不是隐藏的功能!我不认识喜欢他们的人。前段时间在p5p上的一个线程讨论了推定的m / $ foo / r标志的有用性,其中/ r表示没有插值(字母并不重要),因为没有人会记住单引号。
dland

2
@dland:同意;我称这些隐藏的错误功能为特色,并且永远不会在生产代码中使用它们。
Michael Carman

7
我无法想象Perl程序员无法记住(甚至猜测)单引号不代表插值。它的这种语义的用法是在语言几乎是普遍的,我宁愿希望这是如此...
孙大信-恢复莫妮卡

如果模式为空,并且最后一次成功的匹配是使用/ o修饰符编译的,则此后它将停留在该模式上。
davidnicol,

1
我认为空模式行为已被弃用。主要是因为当$ foo为空时,像m / $ foo /这样的模式会变成一个讨厌的错误。
马修·S

12

空文件句柄菱形运算符 <>在构建命令行工具中占有一席之地。它的作用类似于<FH>从句柄中读取内容,只是它神奇地选择了最先找到的那个:命令行文件名或STDIN。取自perlop:

while (<>) {
...         # code for each line
}

4
它还遵循UNIX语义,即使用“-”表示从stdin读取。因此,您可以这样做perl myscript.pl file1.txt - file2.txt,并且perl将处理第一个文件,然后处理stdin,然后处理第二个文件。
瑞安C.汤普森

你可以overload<>你自己的对象操作符(<$var>)像一个迭代的工作。但是,它在列表上下文中无法正常工作。
支石墓

11

特殊码块,例如BEGINCHECKEND。它们来自Awk,但在Perl中的工作方式有所不同,因为它不是基于记录的。

BEGIN块可用于为解析阶段指定一些代码。当您执行语法和变量检查时,也会执行它perl -c。例如,要加载配置变量:

BEGIN {
    eval {
        require 'config.local.pl';
    };
    if ($@) {
        require 'config.default.pl';
    }
}

11
rename("$_.part", $_) for "data.txt";

将data.txt.part重命名为data.txt,而无需重复我自己。


10

代字号-代字号“运算符”有点晦涩难懂,它强制执行标量上下文。

print ~~ localtime;

是相同的

print scalar localtime;

和不同

print localtime;

5
这尤其晦涩,因为perl5.10.0还引入了“智能匹配运算符” ~~,它可以进行正则表达式匹配,可以查看数组中是否包含某项,依此类推。
莫里茨

这并不是很模糊,而是被混淆了(对高尔夫和JAPH有用)。
迈克尔·卡曼

这是不对的!~~在参考文献上并不安全!它对它们进行了字符串化。
Leon Timmermans

嗯,是。字符串化是当引用进入标量上下文时会发生什么情况。如何使“ ~~强制标量上下文”不正确?
Dave Sherohman

3
@Nomad Dervish:标量上下文/ =字符串化。例如,“ $ n = @a”是标量上下文。“ $ s = qq'@ a'”是字符串化。关于引用,“ $ ref1 = $ ref2”是标量上下文,但不是字符串化。
Michael Carman


9

Perl的循环控制构造的“绝望模式”使它们查找堆栈以找到匹配的标签,这允许Test :: More利用它,无论好坏,都有一些奇怪的行为。

SKIP: {
    skip() if $something;

    print "Never printed";
}

sub skip {
    no warnings "exiting";
    last SKIP;
}

有鲜为人知的.pmc文件。“使用Foo”将在Foo.pm之前在@INC中查找Foo.pmc。这样做的目的是允许首先加载已编译的字节码,但是Module :: Compile可以利用此优势来缓存源过滤的模块,以加快加载时间并简化调试。

将警告变成错误的能力。

local $SIG{__WARN__} = sub { die @_ };
$num = "two";
$sum = 1 + $num;
print "Never reached";

这就是我从未想到的想法。


9

山羊胡子操作员*

$_ = "foo bar";
my $count =()= /[aeiou]/g; #3

要么

sub foo {
    return @_;
}

$count =()= foo(qw/a b c d/); #4

之所以有效,是因为标量上下文中的列表分配会产生要分配的列表中元素的数量。

* 注意,不是真正的运算符


那是有史以来(最多,最少)美丽的“操作员”。
克里斯·卢茨
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.