Ada*_*ire 143 perl hidden-features
Perl中有哪些非常有用但却深奥的语言功能,你实际上可以用来做有用的工作?
指南:
(这些都来自Corion的回答)
运营商:
++和一元-运营商处理字符串m//运营商的特殊情况引用结构:
语法和名称:
模块,Pragma和命令行选项:
变量:
循环和流量控制:
常用表达:
其他特性:
其他技巧和元答案:
也可以看看:
Joh*_*usa 54
触发器操作符用于在循环文件句柄返回的记录(通常是行)时跳过第一次迭代,而不使用标志变量:
while(<$fh>)
{
next if 1..1; # skip first record
...
}
Run Code Online (Sandbox Code Playgroud)
运行perldoc perlop并搜索"触发器"以获取更多信息和示例.
mor*_*itz 47
Perl中有许多非显而易见的功能.
例如,你知道sigil之后可以有一个空格吗?
$ perl -wle 'my $x = 3; print $ x'
3
Run Code Online (Sandbox Code Playgroud)
或者,如果使用符号引用,您可以给出子数字名称?
$ perl -lwe '*4 = sub { print "yes" }; 4->()'
yes
Run Code Online (Sandbox Code Playgroud)
还有"bool"准运算符,它返回1表示真实表达式,空字符串表示false:
$ perl -wle 'print !!4'
1
$ perl -wle 'print !!"0 but true"'
1
$ perl -wle 'print !!0'
(empty line)
Run Code Online (Sandbox Code Playgroud)
其他有趣的东西:use overload你可以重载字符串文字和数字(例如使它们成为BigInts或其他).
这些东西中的许多实际上是在某处记录的,或者从逻辑上遵循记录的特征,但是有些并不是很清楚.
更新:另一个不错的.在q{...}引用结构下面提到了,但你知道你可以用字母作为分隔符吗?
$ perl -Mstrict -wle 'print q bJet another perl hacker.b'
Jet another perl hacker.
Run Code Online (Sandbox Code Playgroud)
同样,您可以编写正则表达式:
m xabcx
# same as m/abc/
Run Code Online (Sandbox Code Playgroud)
tim*_*kay 46
通过magic 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;
Run Code Online (Sandbox Code Playgroud)
(引用带有shell元字符的文件名所需的$ _左右的引号)
现在,该<>功能将解压缩@ARGV以".gz"或".Z"结尾的所有文件:
while (<>) {
print;
}
Run Code Online (Sandbox Code Playgroud)
pjf*_*pjf 40
Perl中我最喜欢的一个功能是使用布尔||运算符在一组选项之间进行选择.
$x = $a || $b;
# $x = $a, if $a is true.
# $x = $b, otherwise
Run Code Online (Sandbox Code Playgroud)
这意味着可以写:
$x = $a || $b || $c || 0;
Run Code Online (Sandbox Code Playgroud)
取从所述第一真值$a,$b和$c,或者一个默认0否则.
在Perl 5.10中,还有//操作符,如果已定义则返回左侧,否则返回右侧.以下选择第一限定从值$a,$b,$c,或0以其他方式:
$x = $a // $b // $c // 0;
这些也可以与他们的简写形式一起使用,这对于提供默认值非常有用:
$x ||= 0; # If $x was false, it now has a value of 0. $x //= 0; # If $x was undefined, it now has a value of zero.
Cheerio,
保罗
Leo*_*ans 39
运算符++和一元 - 不仅可以处理数字,还可以处理字符串.
my $_ = "a"
print -$_
Run Code Online (Sandbox Code Playgroud)
打印-a
print ++$_
Run Code Online (Sandbox Code Playgroud)
打印b
$_ = 'z'
print ++$_
Run Code Online (Sandbox Code Playgroud)
打印aa
Cor*_*ion 36
由于Perl几乎所有的"深奥"部分来自其他列表,我会告诉你Perl不能做的一件事:
Perl不能做的一件事就是在代码中有任意URL,因为//运算符用于正则表达式.
为了防止Perl提供的功能不明显,这里有一些可能不是很明显的选项列表:
可移植性和标准性 - 使用Perl的计算机可能多于使用C编译器的计算机
文件/路径操作类 - File :: Find可以在比.Net更多的操作系统上运行
用于以空格分隔的列表 和字符串的引号 - Perl允许您为列表和字符串分隔符选择几乎任意的引号
可替换的命名空间 - Perl通过glob赋值:
*My::Namespace:: = \%Your::Namespace
Run Code Online (Sandbox Code Playgroud)
静态初始化程序 - 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' )
Run Code Online (Sandbox Code Playgroud)
*foo = sub { print "Hello world" };
Run Code Online (Sandbox Code Playgroud)
每当你调用"不存在"函数时调用的魔术方法 - Perl在AUTOLOAD函数中实现它
符号引用 - 建议您远离这些.他们会吃你的孩子.但是,当然,Perl允许您为您的孩子提供嗜血的恶魔.
一行值交换 - Perl允许列表分配
use subs 'unlink';
sub unlink { print 'No.' }
Run Code Online (Sandbox Code Playgroud)
要么
BEGIN{
*CORE::GLOBAL::unlink = sub {print 'no'}
};
unlink($_) for @ARGV
Run Code Online (Sandbox Code Playgroud)
Rob*_*t P 31
在Perl中引用几乎任何类型的奇怪字符串都很简单.
my $url = q{http://my.url.com/any/arbitrary/path/in/the/url.html};
Run Code Online (Sandbox Code Playgroud)
事实上,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.);
Run Code Online (Sandbox Code Playgroud)
报价机制:
q:字面引用; 只有需要转义的字符才是结束字符.qq:解释性引用; 处理变量和转义字符.非常适合您需要引用的字符串:
my $var4 = qq{This "$mechanism" is broken. Please inform "$user" at "$email" about it.};
Run Code Online (Sandbox Code Playgroud)
qx:像qq一样工作,但后来作为系统命令执行,非交互式.返回从标准输出生成的所有文本.(重定向,如果在操作系统中受支持,也会出现)也使用后引号(`字符).
my $output = qx{type "$path"}; # get just the output
my $moreout = qx{type "$path" 2>&1}; # get stuff on stderr too
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
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) ];
Run Code Online (Sandbox Code Playgroud)
只要它能让事情变得更清晰,它们就能很好地使用它们.对于qx,qq和q,我很可能使用{}运算符.使用qw的人最常见的习惯通常是()运算符,但有时你也会看到qw //.
tim*_*kay 27
"for"语句的使用方法与Pascal中使用的"with"相同:
for ($item)
{
s/&?nbsp;/ /g;
s/<.*?>/ /g;
$_ = join(" ", split(" ", $_));
}
Run Code Online (Sandbox Code Playgroud)
您可以将一系列s ///操作等应用于同一变量,而无需重复变量名称.
注意:上面的非中断空格( )中隐藏了Unicode以规避Markdown.不要复制贴吧:)
dla*_*and 26
引号运算符是我最喜欢的东西之一.相比:
my @list = ('abc', 'def', 'ghi', 'jkl');
Run Code Online (Sandbox Code Playgroud)
和
my @list = qw(abc def ghi jkl);
Run Code Online (Sandbox Code Playgroud)
噪音更少,眼睛更容易.关于Perl的另一个非常好的事情,一个在编写SQL时真的错过了,是一个尾随逗号是合法的:
print 1, 2, 3, ;
Run Code Online (Sandbox Code Playgroud)
这看起来很奇怪,但如果你以另一种方式缩进代码则不行:
print
results_of_foo(),
results_of_xyzzy(),
results_of_quux(),
;
Run Code Online (Sandbox Code Playgroud)
在函数调用中添加一个额外的参数不需要在前一行或尾随行上使用逗号.单线更改对其周围线没有影响.
这使得使用可变参数函数非常愉快.这可能是Perl评价最低的功能之一.
小智 26
解析直接粘贴到DATA块的数据的能力.无需保存到要在程序中打开的测试文件或类似文件.例如:
my @lines = <DATA>;
for (@lines) {
print if /bad/;
}
__DATA__
some good data
some bad data
more good data
more good data
Run Code Online (Sandbox Code Playgroud)
Bru*_*ine 24
二进制"x"是重复运算符:
print '-' x 80; # print row of dashes
Run Code Online (Sandbox Code Playgroud)
它也适用于列表:
print for (1, 4, 9) x 3; # print 149149149
Run Code Online (Sandbox Code Playgroud)
Axe*_*man 24
我想说扩展语言的能力,创建伪块操作就是其中之一.
您声明了一个sub的原型,表明它首先需要一个代码引用:
sub do_stuff_with_a_hash (&\%) {
my ( $block_of_code, $hash_ref ) = @_;
while ( my ( $k, $v ) = each %$hash_ref ) {
$block_of_code->( $k, $v );
}
}
Run Code Online (Sandbox Code Playgroud)然后你可以像这样在身体中调用它
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
;
Run Code Online (Sandbox Code Playgroud)(Data::Dumper::Dumper是另一个半隐藏的宝石.)注意你不需要sub在块前面的关键字,或哈希前的逗号.最终看起来很像:map { } @list
此外,还有源过滤器.Perl会将代码传递给您,以便您可以操作它.这个以及块操作都是非常不尝试这种在家的类型.
我已经使用源过滤器做了一些巧妙的事情,例如创建一个非常简单的语言来检查时间,允许简短的Perl单行进行一些决策:
perl -MLib::DB -MLib::TL -e 'run_expensive_database_delete() if $hour_of_day < AM_7';
Run Code Online (Sandbox Code Playgroud)
Lib::TL 只会扫描"变量"和常量,创建它们并根据需要替换它们.
同样,源过滤器可能很混乱,但功能强大.但它们可能会使调试程序变得糟糕 - 甚至可能会使用错误的行号打印警告.我停止使用Damian的Switch,因为调试器将无法告诉我我到底在哪里.但我发现你可以通过修改一小段代码来最小化损坏,使它们保持在同一条线上.
这通常已经足够了,但并不是那么明显.这是一个捎带旧的模具处理程序.
my $old_die_handler = $SIG{__DIE__};
$SIG{__DIE__}
= sub { say q(Hey! I'm DYIN' over here!); goto &$old_die_handler; }
;
Run Code Online (Sandbox Code Playgroud)
这意味着每当代码中的某个其他模块想要死时,它们就会来找你(除非其他人进行破坏性覆盖$SIG{__DIE__}).并且可以通知您有些事情是错误的.
当然,对于足够多的东西,你可以只使用一个END { }块,如果你想做的只是清理.
overload::constant您可以在包含模块的包中检查特定类型的文字.例如,如果你在importsub中使用它:
overload::constant
integer => sub {
my $lit = shift;
return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit
};
Run Code Online (Sandbox Code Playgroud)
这意味着调用包中每个大于20亿的整数都将被更改为一个Math::BigInt对象.(参见overload :: constant).
虽然我们正在努力.Perl允许您将大数字分成三个数字的组,并且仍然可以获得一个可解析的整数.注意2_000_000_000上面有20亿.
And*_*isi 24
污点检查.启用污点检查后,-t如果您尝试将污染数据(粗略地说,来自程序外部的数据)传递给不安全的功能(打开文件,运行外部命令等),perl将会死亡(或发出警告).在编写setuid脚本或CGI或脚本具有比提供数据的人更多特权的任何内容时,它非常有用.
魔术转到. goto &sub做一个优化的尾调用.
调试器.
use strict和use warnings.这些可以帮助您摆脱一堆拼写错误.
Sec*_*Sec 22
基于Perl 5中的"-n"和"-p"交换机的实现方式,您可以编写一个看似不正确的程序,包括}{:
ls |perl -lne 'print $_; }{ print "$. Files"'
Run Code Online (Sandbox Code Playgroud)
在内部转换为此代码:
LINE: while (defined($_ = <ARGV>)) {
print $_; }{ print "$. Files";
}
Run Code Online (Sandbox Code Playgroud)
Sec*_*Sec 18
让我们从宇宙飞船运营商那里开始.
$a = 5 <=> 7; # $a is set to -1
$a = 7 <=> 5; # $a is set to 1
$a = 6 <=> 6; # $a is set to 0
Run Code Online (Sandbox Code Playgroud)
pjf*_*pjf 18
这是一个元答案,但Perl Tips档案包含可以使用Perl完成的各种有趣的技巧.以前的提示存档是在线浏览,可以通过邮件列表或原子订阅订阅.
我最喜欢的一些技巧包括使用PAR构建可执行文件,使用autodie自动抛出异常,以及在Perl 5.10中使用switch和smart-match构造.
披露:我是Perl Tips的作者和维护者之一,所以我显然非常重视它们.;)
小智 15
循环上的continue子句.它将在每个循环的底部执行,即使是下一个循环.
while( <> ){
print "top of loop\n";
chomp;
next if /next/i;
last if /last/i;
print "bottom of loop\n";
}continue{
print "continue\n";
}
Run Code Online (Sandbox Code Playgroud)
Mic*_*man 13
该m//运营商有一些模糊的特殊情况:
?分隔符,除非您致电,否则它只匹配一次reset.'用作分隔符,则不插入模式.J.J*_*.J. 13
while(/\G(\b\w*\b)/g) {
print "$1\n";
}
Run Code Online (Sandbox Code Playgroud)
\ G锚.它是热的.
spo*_*son 12
null filehandle 菱形运算符 <>在构建命令行工具中占有一席之地.它的作用就像<FH>是从句柄中读取,除了它神奇地选择最先找到的那个:命令行文件名或STDIN.摘自perlop:
while (<>) {
... # code for each line
}
Run Code Online (Sandbox Code Playgroud)
Bru*_*ine 11
特殊的代码块,如BEGIN,CHECK和END.它们来自Awk,但在Perl中的工作方式不同,因为它不是基于记录的.
该BEGIN块可用于为解析阶段指定一些代码; 执行语法和变量检查时也会执行它perl -c.例如,要加载配置变量:
BEGIN {
eval {
require 'config.local.pl';
};
if ($@) {
require 'config.default.pl';
}
}
Run Code Online (Sandbox Code Playgroud)
tim*_*kay 11
rename("$_.part", $_) for "data.txt";
Run Code Online (Sandbox Code Playgroud)
将data.txt.part重命名为data.txt而不必重复自己.
Sec*_*Sec 10
有点模糊的是波形符号"操作符",它强制标量上下文.
print ~~ localtime;
Run Code Online (Sandbox Code Playgroud)
是相同的
print scalar localtime;
Run Code Online (Sandbox Code Playgroud)
与...不同
print localtime;
Run Code Online (Sandbox Code Playgroud)
Perl的循环控制构造的"绝望模式"导致它们查找堆栈以找到匹配的标签,这允许一些好奇的行为,Test :: More利用了这些行为,无论好坏.
SKIP: {
skip() if $something;
print "Never printed";
}
sub skip {
no warnings "exiting";
last SKIP;
}
Run Code Online (Sandbox Code Playgroud)
有一个鲜为人知的.pmc文件."使用Foo"将在Foo.pm之前在@INC中查找Foo.pmc. 这是为了允许首先加载已编译的字节码,但Module :: Compile利用此功能来缓存源过滤的模块,以加快加载速度并简化调试.
将警告变为错误的能力.
local $SIG{__WARN__} = sub { die @_ };
$num = "two";
$sum = 1 + $num;
print "Never reached";
Run Code Online (Sandbox Code Playgroud)
这就是我能想到的没有被提及的头脑.
山羊运营商*:
$_ = "foo bar";
my $count =()= /[aeiou]/g; #3
Run Code Online (Sandbox Code Playgroud)
要么
sub foo {
return @_;
}
$count =()= foo(qw/a b c d/); #4
Run Code Online (Sandbox Code Playgroud)
它的工作原理是因为标量上下文中的列表赋值会产生所分配列表中的元素数.
* 注意,不是真正的操作员
小智 9
输入记录分隔符可以设置为对数字的引用以读取固定长度记录:
$/ = \3; print $_,"\n" while <>; # output three chars on each line
Run Code Online (Sandbox Code Playgroud)
这个并不是特别有用,但它非常深奥.我在Perl解析器中挖掘时偶然发现了这一点.
在有POD之前,perl4有一个技巧允许你将手册页(如nroff)直接嵌入你的程序中,这样它就不会丢失.perl4使用了一个名为wrapman的程序(请参阅Pink Camel第319页了解一些细节),巧妙地将nroff手册页嵌入到脚本中.
它的工作原理是告诉nroff忽略所有代码,然后在END标记之后放置man页面的内容,告诉Perl停止处理代码.看起来像这样:
#!/usr/bin/perl
'di';
'ig00';
...Perl code goes here, ignored by nroff...
.00; # finish .ig
'di \" finish the diversion
.nr nl 0-1 \" fake up transition to first page
.nr % 0 \" start at page 1
'; __END__
...man page goes here, ignored by Perl...
Run Code Online (Sandbox Code Playgroud)
roff魔法的细节让我感到惊讶,但你会发现roff命令是void上下文中的字符串或数字.通常,void上下文中的常量会产生警告.op.c允许使用以某些roff命令开头的void上下文字符串有一些特殊的例外.
/* perl4's way of mixing documentation and code
(before the invention of POD) was based on a
trick to mix nroff and perl code. The trick was
built upon these three nroff macros being used in
void context. The pink camel has the details in
the script wrapman near page 319. */
const char * const maybe_macro = SvPVX_const(sv);
if (strnEQ(maybe_macro, "di", 2) ||
strnEQ(maybe_macro, "ds", 2) ||
strnEQ(maybe_macro, "ig", 2))
useless = NULL;
Run Code Online (Sandbox Code Playgroud)
这意味着,'di';不产生警告,但同样没有'die'; 'did you get that thing I sentcha?';或'ignore this line';.
此外,还有用于数字常量例外0和1允许裸露.00;.该代码声称这是出于更一般的目的.
/* the constants 0 and 1 are permitted as they are
conventionally used as dummies in constructs like
1 while some_condition_with_side_effects; */
else if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
useless = NULL;
Run Code Online (Sandbox Code Playgroud)
你知道什么,2 while condition警告!
您可以使用@ {[...]}来获得复杂perl表达式的插值结果
$a = 3;
$b = 4;
print "$a * $b = @{[$a * $b]}";
Run Code Online (Sandbox Code Playgroud)
打印: 3 * 4 = 12
sub load_file
{
local(@ARGV, $/) = shift;
<>;
}
Run Code Online (Sandbox Code Playgroud)
以及适当返回数组的版本:
sub load_file
{
local @ARGV = shift;
local $/ = wantarray? $/: undef;
<>;
}
Run Code Online (Sandbox Code Playgroud)
use diagnostics;
Run Code Online (Sandbox Code Playgroud)
如果您开始使用Perl并且之前从未这样做过,那么这个模块将为您节省大量时间和麻烦.对于您可以获得的几乎所有基本错误消息,此模块将为您提供有关代码中断的原因的冗长解释,包括有关如何修复它的一些有用提示.例如:
use strict;
use diagnostics;
$var = "foo";
Run Code Online (Sandbox Code Playgroud)
给你这个有用的信息:
Global symbol "$var" requires explicit package name at - line 4.
Execution of - aborted due to compilation errors (#1)
(F) You've said "use strict vars", which indicates that all variables
must either be lexically scoped (using "my"), declared beforehand using
"our", or explicitly qualified to say which package the global variable
is in (using "::").
Uncaught exception from user code:
Global symbol "$var" requires explicit package name at - line 4.
Execution of - aborted due to compilation errors.
at - line 5
use diagnostics;
use strict;
sub myname {
print { " Some Error " };
};
Run Code Online (Sandbox Code Playgroud)
你得到这个大而有用的文本块:
syntax error at - line 5, near "};"
Execution of - aborted due to compilation errors (#1)
(F) Probably means you had a syntax error. Common reasons include:
A keyword is misspelled.
A semicolon is missing.
A comma is missing.
An opening or closing parenthesis is missing.
An opening or closing brace is missing.
A closing quote is missing.
Often there will be another error message associated with the syntax
error giving more information. (Sometimes it helps to turn on -w.)
The error message itself often tells you where it was in the line when
it decided to give up. Sometimes the actual error is several tokens
before this, because Perl is good at understanding random input.
Occasionally the line number may be misleading, and once in a blue moon
the only way to figure out what's triggering the error is to call
perl -c repeatedly, chopping away half the program each time to see
if the error went away. Sort of the cybernetic version of S.
Uncaught exception from user code:
syntax error at - line 5, near "};"
Execution of - aborted due to compilation errors.
at - line 7
从那里你可以去推断你的程序可能出现什么问题(在这种情况下,打印格式完全错误).诊断中存在大量已知错误.现在,虽然这在生产中使用不是一件好事,但对于那些刚接触Perl的人来说,它可以作为一个很好的学习辅助工具.
还有$ [变量决定数组的起始索引.默认值为0,因此数组从0开始.通过设置
$[=1;
Run Code Online (Sandbox Code Playgroud)
如果你真的想要,你可以让Perl表现得更像AWK(或Fortran).
小智 5
@Schwern提到通过本地化将警告转化为错误$SIG{__WARN__}.你也可以这样做(词法)use warnings FATAL => "all";.见perldoc lexwarn.
在那个音符上,自从Perl 5.12以来,你已经能够说perldoc foo而不是完整了perldoc perlfoo.最后!:)
| 归档时间: |
|
| 查看次数: |
59317 次 |
| 最近记录: |