Các tính năng ẩn của Perl?


143

Một số tính năng ngôn ngữ thực sự hữu ích nhưng bí truyền trong Perl mà bạn thực sự có thể sử dụng để làm công việc hữu ích là gì?

Hướng dẫn:

  • Cố gắng giới hạn câu trả lời cho lõi Perl chứ không phải CPAN
  • Hãy cho một ví dụ và một mô tả ngắn

Các tính năng ẩn cũng được tìm thấy trong các tính năng ẩn của các ngôn ngữ khác:

(Đây là tất cả từ câu trả lời của Corion )

  • C
    • Thiết bị của Duff
    • Tính di động và tiêu chuẩn
  • C #
    • Báo giá cho danh sách và chuỗi phân cách khoảng trắng
    • Không gian tên bí danh
  • Java
    • Thuốc kích thích tĩnh
  • JavaScript
    • Chức năng là công dân hạng nhất
    • Phạm vi khối và đóng cửa
    • Gọi phương thức và bộ truy cập gián tiếp thông qua một biến
  • Hồng ngọc
    • Xác định phương thức thông qua mã
  • PHP
    • Tài liệu trực tuyến phổ biến
    • Phương pháp ma thuật
    • Tài liệu tham khảo tượng trưng
  • Con trăn
    • Trao đổi giá trị một dòng
    • Khả năng thay thế ngay cả các chức năng cốt lõi bằng chức năng của riêng bạn

Các tính năng ẩn khác:

Toán tử:

Trích dẫn cấu trúc:

Cú pháp và tên:

Các mô-đun, thực dụng và các tùy chọn dòng lệnh:

Biến:

Vòng lặp và kiểm soát dòng chảy:

Biểu thức chính quy:

Các tính năng khác:

Các thủ thuật khác và câu trả lời meta:


Xem thêm:


Hầu hết các tính năng này được sử dụng hàng ngày, một số tính năng xuất hiện trong phần lớn các tập lệnh Perl và hầu hết được liệt kê trong phần "Khác" vẫn xuất phát từ các ngôn ngữ khác, việc gọi những "ẩn" này làm thay đổi ý định của câu hỏi.
rebierpost

Câu trả lời:


54

Toán tử flip-flop rất hữu ích để bỏ qua lần lặp đầu tiên khi lặp qua các bản ghi (thường là các dòng) được trả về bởi một tệp xử lý tệp, mà không sử dụng biến cờ:

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

Chạy perldoc perlopvà tìm kiếm "flip-flop" để biết thêm thông tin và ví dụ.


Trên thực tế, đó được lấy từ Awk, nơi bạn có thể thực hiện lật giữa hai mẫu bằng cách viết mẫu1, mẫu2
Bruno De Fraine

15
Để làm rõ, khía cạnh "ẩn" của điều này là nếu một toán hạng cho vô hướng '..' là một hằng số thì giá trị được so sánh ngầm với số dòng đầu vào ($.)
Michael Carman

47

Có nhiều tính năng không rõ ràng trong Perl.

Ví dụ, bạn có biết rằng có thể có một khoảng trống sau một sigil không?

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

Hoặc bạn có thể cung cấp tên số phụ nếu bạn sử dụng tài liệu tham khảo tượng trưng?

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

Ngoài ra còn có toán tử gần đúng "bool", trả về 1 cho các biểu thức đúng và chuỗi trống cho false:

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

Các nội dung thú vị khác: với use overloadbạn có thể quá tải chuỗi ký tự và số (và ví dụ: biến chúng thành BigInts hoặc bất cứ thứ gì).

Nhiều trong số những điều này thực sự được ghi lại ở đâu đó, hoặc theo logic từ các tính năng được ghi lại, nhưng dù sao một số không được biết đến nhiều.

Cập nhật : Một số tốt đẹp. Bên dưới các q{...}cấu trúc trích dẫn đã được đề cập, nhưng bạn có biết rằng bạn có thể sử dụng các chữ cái làm dấu phân cách không?

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

Tương tự như vậy, bạn có thể viết các biểu thức thông thường:

m xabcx
# same as m/abc/

2
Bạn có biết rằng có thể có một khoảng trống sau một sigil không? Tôi hoàn toàn lúng túng. Ồ
Aristotle Pagaltzis

1
Mát mẻ! !! $ undef_var không tạo cảnh báo.
Axeman

4
Tôi nghĩ rằng ví dụ của bạn về việc sử dụng các chữ cái để phân định các chuỗi phải là " Chỉ là một hacker perl khác" chứ không phải là "Jet một hacker khác perl" = P
Chris Lutz

Phần tồi tệ nhất là bạn cũng có thể sử dụng những thứ khác như dấu phân cách. Ngay cả dấu ngoặc đóng. Sau đây là hợp lệ: s} regex} thay thế} xsmg; q] chuỗi ký tự];
Ryan C. Thompson

46

Thêm hỗ trợ cho các tệp nén thông qua ARGV ma thuật :

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;

(trích dẫn khoảng $ _ cần thiết để xử lý tên tệp có ký tự đại diện shell trong)

Bây giờ <>tính năng này sẽ giải nén bất kỳ @ARGVtệp nào kết thúc bằng ".gz" hoặc ".Z":

while (<>) {
    print;
}

2
Tôi không nghĩ rằng bạn cần phải thoát khỏi |sự thay thế.
Chris Lutz

Tôi đang nhìn chằm chằm vào điều này và tôi không thể tìm ra cách nó hoạt động. Tại điểm nào được zcat |phân tích cú pháp như một lệnh để dẫn qua?
Ether

1
@Ether => phát hiện các đường ống là một tính năng của hai đối số mở, mà toán tử kim cương sử dụng khi nó mở từng tệp trong@ARGV
Eric Strom

40

Một trong những tính năng yêu thích của tôi trong Perl là sử dụng toán ||tử boolean để chọn giữa một tập hợp các lựa chọn.

 $x = $a || $b;

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

Điều này có nghĩa là người ta có thể viết:

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

lấy giá trị đầu tiên đúng từ $a, $b$c, hoặc mặc định 0khác.

Trong Perl 5.10, cũng có //toán tử, trả về phía bên trái nếu được xác định và phía bên phải khác. Sau đây chọn định nghĩa đầu tiên giá trị từ $a, $b, $c, hoặc 0bằng cách khác:

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

Chúng cũng có thể được sử dụng với các hình thức tay ngắn của chúng, rất hữu ích để cung cấp mặc định:

$ x || = 0; # Nếu $ x là sai, bây giờ nó có giá trị 0.

$ x // = 0; # Nếu $ x không được xác định, bây giờ nó có giá trị bằng không.

Cổ vũ

Paul


4
Đây là một thành ngữ phổ biến đến nỗi nó hầu như không đủ điều kiện là một tính năng "ẩn".
Michael Carman

3
xấu hổ vì máy in đẹp nghĩ // là một bình luận :)
John Ferguson

2
Câu hỏi, có "tính năng sử dụng" để sử dụng các toán tử mới này hay chúng được bật mặc định? Tôi vẫn đang nghiêng về các tính năng của Perl 5.10.
JJ

6
// ở trong đó theo mặc định, không cần chỉnh sửa đặc biệt. Bạn cũng có thể backport nó thành 5.8.x với dor-patch ... xem thư mục tác giả / id / H / HM / HMBRAND / trên bất kỳ máy nhân bản CPAN nào. FreeBSD 6.x và hơn thế nữa làm điều này cho bạn trong gói perl của họ.
dland

2
Khi nào | | hoặc // được kết hợp với do {}, bạn có thể gói gọn một phép gán phức tạp hơn, tức là $ x = $ a || làm {của tôi $ z; 3 hoặc 4 dòng phái sinh; $ z};
RET

39

Các toán tử ++ và unary - không chỉ hoạt động trên các số, mà còn trên các chuỗi.

my $_ = "a"
print -$_

in -a

print ++$_

in b

$_ = 'z'
print ++$_

in aa


3
Để trích dẫn perlvar: "Toán tử tự động giảm không phải là phép thuật." Vì vậy, --không làm việc trên chuỗi.
moritz

"Aa" dường như không phải là yếu tố tự nhiên theo sau "z". Tôi mong đợi giá trị ascii cao nhất tiếp theo, đó là "{".
Ether

4
Đừng hỏi một lập trình viên sau "z"; hỏi một con người Tính năng này rất tốt cho việc đánh số các mục trong một danh sách dài.
Barry Brown

17
Khi mới sử dụng Perl, tôi đã tự mình thực hiện tính năng này với hành vi từ z đến aa chính xác, sau đó cho một đồng nghiệp cười và nói với tôi rằng "hãy để tôi chỉ cho bạn điều gì đó". Tôi đã khóc một chút nhưng học được điều gì đó.
Copas

2
@Ether - Nếu bạn muốn điều đó, hãy sử dụng số và tự động chuyển chúng sang ASCII với ord(). Hoặc, viết một lớp nhỏ và quá tải các toán tử để làm điều đó cho bạn.
Chris Lutz

36

Vì Perl có hầu hết tất cả các phần "bí truyền" từ các danh sách khác, tôi sẽ nói với bạn một điều mà Perl không thể:

Điều duy nhất Perl không thể làm là có các URL tùy ý trong mã của bạn, bởi vì // toán tử được sử dụng cho các biểu thức thông thường.

Trong trường hợp không rõ ràng với bạn những tính năng mà Perl cung cấp, đây là danh sách chọn lọc của các mục có thể không hoàn toàn rõ ràng:

Thiết bị của Duff - bằng Perl

Tính di động và tiêu chuẩn - Có khả năng nhiều máy tính có Perl hơn so với trình biên dịch C

Một lớp thao tác tệp / đường dẫn - File :: Find hoạt động trên nhiều hệ điều hành hơn so với .Net không

Báo giá cho danh sách phân cách khoảng trắng và chuỗi - Perl cho phép bạn chọn các trích dẫn gần như tùy ý cho danh sách và phân cách chuỗi của bạn

Không gian tên bí danh danh - Perl có những điều này thông qua các bài tập toàn cầu:

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

Bộ khởi tạo tĩnh - Perl có thể chạy mã trong hầu hết mọi giai đoạn biên dịch và khởi tạo đối tượng, từ BEGIN(phân tích mã) đến CHECK(sau khi phân tích mã) đến import(khi nhập mô-đun) đếnnew (khởi tạo đối tượng) đến DESTROY(hủy đối tượng) đến END(thoát chương trình)

Chức năng là công dân hạng nhất - giống như trong Perl

Phạm vi khối và đóng cửa - Perl có cả hai

Gọi phương thức và bộ truy cập gián tiếp thông qua một biến - Perl cũng vậy:

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

Xác định phương thức thông qua mã - Perl cũng cho phép điều đó :

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

Tài liệu trực tuyến phổ biến - Perl trực tuyến và có khả năng trên hệ thống của bạn

Các phương thức ma thuật được gọi bất cứ khi nào bạn gọi hàm "không tồn tại" - Perl thực hiện điều đó trong hàm AUTOLOAD

Tài liệu tham khảo tượng trưng - bạn nên tránh xa những thứ này. Họ sẽ ăn con của bạn. Nhưng tất nhiên, Perl cho phép bạn dâng con cho những con quỷ khát máu.

Trao đổi giá trị một dòng - Perl cho phép gán danh sách

Khả năng thay thế ngay cả các chức năng cốt lõi bằng chức năng của riêng bạn

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

hoặc là

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

unlink($_) for @ARGV

Tôi là người hâm mộ tài liệu của Perl so với các ngôn ngữ khác, nhưng tôi vẫn nghĩ rằng đối với Regexes và tài liệu tham khảo, nó có thể được hợp lý hóa rất nhiều. ví dụ: mồi tốt nhất cho regexes không phải là Perlre, mà là Perlop
John Ferguson

9
"Một điều mà Perl không thể làm là có các URL tùy ý trong mã của bạn, bởi vì toán tử // được sử dụng cho các biểu thức thông thường." - điều này là hoàn toàn vô nghĩa.

Cảm ơn sự hiểu biết của bạn. Tôi đã xem xét một số cách để có một URL http: // ... trong mã Perl mà không sử dụng bộ lọc nguồn và không tìm thấy cách nào. Bạn có thể chỉ ra cách này là có thể? // được sử dụng cho các biểu thức chính quy trong các phiên bản Perl lên đến 5,8.x. Trong 5.10, nó được định nghĩa lại cho định nghĩa hoặc gán.
Quân đoàn

8
Tại sao / nơi bạn muốn có các URL trần trong mã của mình? Tôi không thể nghĩ ra một ví dụ.
castaway

18
Không ai muốn điều đó, nó chỉ là một meme Java. " foo.com " là nhãn http: và sau đó là "foo.com" trong một bình luận. Một số người thấy điều này thú vị bởi vì ... họ thật ngu ngốc.
jrockway

35

Tự động hóa . AFAIK không có ngôn ngữ khác có nó .


Tôi không biết rằng Python, et al, đã không hỗ trợ điều này.
Skiphoppy

@davidnicol: Thật sao? bạn có thể cung cấp một liên kết? Tìm kiếm nhanh của tôi trên google đã không trả lại bất cứ điều gì. Đối với những người không biết ECMAscript là tên chính xác của Javascript. vi.wikipedia.org/wiki/ECMAScript
JJ

1
Và có một mô-đun để vô hiệu hóa tự động hóa
Alexandr

1
@Gregg Lind - Cho rằng Python tự động tạo các biến bất cứ khi nào bạn gán cho chúng lần đầu tiên, tự động hóa sẽ tạo ra các vấn đề khủng khiếp từ một lỗi đánh máy.
Chris Lutz

3
@tchrist - a = [[x * y cho y trong xrange (1,11)] cho x trong xrange (1,11)]
Omnifarious

31

Thật đơn giản để trích dẫn hầu hết mọi loại chuỗi lạ trong Perl.

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

Trên thực tế, các cơ chế trích dẫn khác nhau trong Perl khá thú vị. Các cơ chế trích dẫn giống như biểu thức Perl cho phép bạn trích dẫn bất cứ điều gì, chỉ định các dấu phân cách. Bạn có thể sử dụng hầu hết mọi ký tự đặc biệt như #, / hoặc mở / đóng các ký tự như (), [] hoặc {}. Ví dụ:

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.);

Cơ chế trích dẫn:

q: trích dẫn bằng chữ; nhân vật duy nhất cần được trốn thoát là nhân vật kết thúc. qq: một trích dẫn được giải thích; xử lý các biến và thoát ký tự. Tuyệt vời cho chuỗi mà bạn cần trích dẫn:

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

qx: Hoạt động như qq, nhưng sau đó thực thi nó như một lệnh hệ thống, không tương tác. Trả về tất cả các văn bản được tạo ra từ tiêu chuẩn ra. (Chuyển hướng, nếu được hỗ trợ trong HĐH, cũng xuất hiện) Cũng được thực hiện với dấu ngoặc kép (ký tự `).

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

qr: Giải thích như qq, nhưng sau đó biên dịch nó thành một biểu thức thông thường. Hoạt động với các tùy chọn khác nhau trên regex là tốt. Bây giờ bạn có thể vượt qua regex xung quanh dưới dạng một biến:

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: Một toán tử trích dẫn rất, rất hữu ích. Biến một tập hợp các từ được phân tách khoảng trắng thành một danh sách. Tuyệt vời để điền dữ liệu trong một bài kiểm tra đơn vị.


   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) ]; 

Chúng thật tuyệt khi sử dụng chúng bất cứ khi nào nó làm cho mọi thứ rõ ràng hơn. Đối với qx, qq và q, rất có thể tôi sử dụng các toán tử {}. Thói quen phổ biến nhất của những người sử dụng qw thường là toán tử (), nhưng đôi khi bạn cũng thấy qw //.


1
Đôi khi tôi sử dụng qw "" để các tô sáng cú pháp sẽ tô sáng nó một cách chính xác.
Brad Gilbert

Làm việc cho tôi trong SlickEdit. :)
Robert P

1
@fengshaun, Các biên tập viên tôi thường sử dụng làm nổi bật những điều này một cách chính xác. Tôi đã tham khảo, một phần là cú pháp tô sáng trên StackOverflow.
Brad Gilbert

@Brad Gilbert: Stack Overflow không thể (tốt, (không) phân tích cú pháp Perl đáng để ngồi xổm. ☹
tchrist

my $moreout = qx{type "$path" 2>&1};... Tôi không biết bạn có thể làm điều đó! [TM]
dland

27

Không thực sự ẩn, nhưng nhiều lập trình viên Perl mỗi ngày không biết về CPAN . Điều này đặc biệt áp dụng cho những người không lập trình toàn thời gian hoặc không lập trình toàn thời gian Perl.


27

Câu lệnh "for" có thể được sử dụng theo cùng một cách "với" được sử dụng trong Pascal:

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

Bạn có thể áp dụng một chuỗi các hoạt động s ///, v.v. cho cùng một biến mà không phải lặp lại tên biến.

LƯU Ý: không gian không phá vỡ ở trên (& nbsp;) đã ẩn Unicode trong đó để phá vỡ Markdown. Đừng sao chép dán nó :)


Và "map" cũng thực hiện thủ thuật tương tự ... map {....} $ item; Một lợi thế của việc sử dụng "cho" trên "bản đồ" là bạn có thể sử dụng tiếp theo để thoát ra.
Drainegtun

2
Ngoài ra, đối với mục đã được thao tác được liệt kê trước khi mã thực hiện thao tác, dẫn đến khả năng đọc tốt hơn.
Robert P

@RobertP: Điều đó hoàn toàn đúng. Một topicalizer là hữu ích trong diễn ngôn.
tchrist

26

Toán tử báo giá là một trong những điều yêu thích của tôi. Đối chiếu:

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

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

Ít tiếng ồn hơn, dễ nhìn hơn. Một điều thực sự thú vị khác về Perl, một điều mà tôi thực sự nhớ khi viết SQL, đó là dấu phẩy kéo dài là hợp pháp:

print 1, 2, 3, ;

Điều đó có vẻ kỳ lạ, nhưng không phải nếu bạn thụt mã theo cách khác:

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

Thêm một đối số bổ sung cho lệnh gọi hàm không yêu cầu bạn phải tìm hiểu bằng dấu phẩy trên các dòng trước hoặc sau. Sự thay đổi dòng đơn không có tác động đến các dòng xung quanh của nó.

Điều này làm cho nó rất dễ chịu để làm việc với các chức năng matrixdic. Đây có lẽ là một trong những tính năng được đánh giá thấp nhất của Perl.


2
Một trường hợp góc thú vị của cú pháp Perl là những điều sau đây là hợp lệ: với $ _ qw (một danh sách các công cụ) {...}
ephemient

1
Bạn thậm chí có thể lạm dụng cú pháp toàn cầu để trích dẫn các từ, miễn là bạn không sử dụng các ký tự đặc biệt như *?. Vì vậy, bạn có thể viếtfor (<a list of stuff>) { ... }
moritz

1
@ephemient: gần. Đó chỉ làm việc với lexicals: cho tôi $ x qw (abc) {...} Ví dụ: với $ _ qw (abc) {print} # in không có gì
dland

tại sao lại thêm từ vựng đó khi bạn có thể thưởng thức mặc định yêu thích của perl? cho (qw / abcd /) {in; }
fengshaun

2
@ephemient, @fengshaun, @moritz, @dland: Đó là cố định của rèn trong blead ; xem chủ đề p5p này .
tchrist

26

Khả năng phân tích dữ liệu được dán trực tiếp vào một khối DATA . Không cần phải lưu vào một tệp thử nghiệm để được mở trong chương trình hoặc tương tự. Ví dụ:

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

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

Và rất hữu ích trong các bài kiểm tra nhỏ!
fengshaun

@peter mortensen làm thế nào bạn có nhiều khối? Và làm thế nào để bạn kết thúc một khối?
cóc

@Toad: đó là câu trả lời của allan (xem danh sách sửa đổi). Nó là tốt hơn để giải quyết người dùng đó. Hoặc, vì người dùng đó đã rời khỏi Stack Overflow, có thể không đề cập đến ai cụ thể (vì vậy một chuyên gia Perl thực sự có thể làm thẳng ra sau).
Peter Mortensen

3
@Hai: Không, nó không xấu - thực tế, nó hoàn toàn trái ngược với sự xấu xí: nó sạch sẽ, mảnh dẻ, tối thiểu và đẹp đẽ; trong một từ, nó thật tuyệt vời và các ngôn ngữ mà không có nó là Pita. @peter mortensen, @toad: Một câu trả lời cho cách có nhiều khối dữ liệu trong cùng một chương trình là sử dụng mô-đun Inline :: Files tắt CPAN.
tchrist

Inline :: Files được triển khai bằng các bộ lọc nguồn. Ngoài ra còn có Dữ liệu :: Phần cung cấp nhiều khối nội tuyến và không sử dụng bộ lọc nguồn.
Prakash K

24

Hoạt động khối mới

Tôi muốn nói khả năng mở rộng ngôn ngữ, tạo ra các hoạt động khối giả là một.

  1. Bạn khai báo nguyên mẫu cho một phụ chỉ ra rằng nó cần tham chiếu mã trước:

    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. Sau đó bạn có thể gọi nó trong cơ thể như vậy

    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::Dumperlà một viên ngọc bán ẩn khác.) Lưu ý cách bạn không cầnsub từ khóa trước khối hoặc dấu phẩy trước hàm băm. Nó kết thúc giống như:map { } @list

Bộ lọc nguồn

Ngoài ra, có các bộ lọc nguồn. Trường hợp Perl sẽ chuyển cho bạn mã để bạn có thể thao tác nó. Cả hai điều này, và các hoạt động khối, là khá nhiều loại không thử ở nhà này.

Tôi đã thực hiện một số điều gọn gàng với các bộ lọc nguồn, ví dụ như tạo một ngôn ngữ rất đơn giản để kiểm tra thời gian, cho phép một lớp lót Perl ngắn cho một số quyết định:

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

Lib::TL sẽ chỉ quét cả "biến" và hằng số, tạo chúng và thay thế chúng khi cần.

Một lần nữa, các bộ lọc nguồn có thể lộn xộn, nhưng rất mạnh mẽ. Nhưng họ có thể gây rối cho trình gỡ lỗi một cái gì đó khủng khiếp - và thậm chí các cảnh báo có thể được in sai số dòng. Tôi đã ngừng sử dụng Damian's Switch vì trình gỡ lỗi sẽ mất tất cả khả năng cho tôi biết tôi thực sự đang ở đâu. Nhưng tôi đã thấy rằng bạn có thể giảm thiểu thiệt hại bằng cách sửa đổi các phần nhỏ của mã, giữ chúng trên cùng một dòng.

Móc tín hiệu

Nó thường được thực hiện đủ, nhưng nó không phải là tất cả rõ ràng. Đây là một người xử lý chết mà cõng trên cái cũ.

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

Điều đó có nghĩa là bất cứ khi nào một số mô-đun khác trong mã muốn chết, chúng phải đến với bạn (trừ khi có người khác thực hiện ghi đè phá hoại $SIG{__DIE__} ). Và bạn có thể được thông báo rằng ai đó một cái gì đó là một lỗi.

Tất nhiên, đối với đủ thứ bạn chỉ có thể sử dụng một END { }khối, nếu tất cả những gì bạn muốn làm là dọn sạch.

overload::constant

Bạn có thể kiểm tra nghĩa đen của một loại nhất định trong các gói bao gồm mô-đun của bạn. Ví dụ: nếu bạn sử dụng điều này trong importphụ của bạn :

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

điều đó có nghĩa là mọi số nguyên lớn hơn 2 tỷ trong các gói gọi sẽ được thay đổi thành một Math::BigIntđối tượng. (Xem quá tải :: không đổi ).

Nhóm nguyên văn

Trong khi chúng ta đang ở đó. Perl cho phép bạn chia số lớn thành các nhóm có ba chữ số và vẫn lấy được một số nguyên có thể phân tích được. Lưu ý 2_000_000_000ở trên với giá 2 tỷ đồng.


5
Khi sử dụng trình xử lý $ SIG { DIE }, chúng tôi khuyên bạn nên kiểm tra $ ^ S để xem chương trình của bạn có thực sự chết hay chỉ ném một ngoại lệ sẽ bị bắt. Thông thường bạn không muốn can thiệp vào cái sau.
pjf

Các khối mới là rất hướng dẫn! Tôi đã nghĩ rằng đó là một ngữ nghĩa ngôn ngữ! cảm ơn nhiều.
ZeroCool

Một hướng dẫn sử dụng của bộ lọc nguồn là NiceSlice của pdl ( pdl.perl.org/?docs=NiceSlice&title=PDL::NiceSlice ) để người ta không cần sử dụng ->slicenhư một phương thức mỗi khi cần một lát.
Joel Berger

24

Nhị phân "x" là toán tử lặp lại :

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

Nó cũng hoạt động với danh sách:

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

Đây là một lý do tại sao Perl đã rất phổ biến với tin tặc. perl -e 'in 0x000 x 25';
JJ

4
Việc sử dụng yêu thích của tôi cho việc này là tạo các trình giữ chỗ cho phần cuối của câu lệnh SQL INSERT: @p = ('?') X $ n; $ p = tham gia (",", @p); $ sql = "CHERTN ... GIÁ TRỊ ($ p)";
Skiphoppy

24

Kiểm tra vết bẩn. Khi bật tính năng kiểm tra, perl sẽ chết (hoặc cảnh báo, với-t ) nếu bạn cố truyền dữ liệu bị nhiễm độc (nói đại khái là dữ liệu từ bên ngoài chương trình) sang một chức năng không an toàn (mở tệp, chạy lệnh bên ngoài, v.v.). Nó rất hữu ích khi viết các tập lệnh setuid hoặc CGI hoặc bất cứ điều gì mà tập lệnh có các đặc quyền lớn hơn so với người cung cấp dữ liệu đó.

Ma thuật goto. goto &subthực hiện một cuộc gọi đuôi được tối ưu hóa.

Trình gỡ lỗi.

use strictuse warnings. Những thứ này có thể cứu bạn khỏi một loạt lỗi chính tả.


1
Tại sao các ngôn ngữ khác không có tính năng này? Tính năng này được sử dụng làm cho các tập lệnh web perl trở nên an toàn hơn.
Khóa Matthew

22

Dựa trên cách thức "-n"và các "-p"công tắc được triển khai trong Perl 5, bạn có thể viết một chương trình dường như không chính xác bao gồm }{:

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

được chuyển đổi nội bộ sang mã này:

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

@martin clayton: Tại sao lại gọi như vậy?
tchrist

@tchrist - vì nó, được cho là, trông như hai người dụi mũi. Trong hồ sơ, nếu bạn thấy những gì tôi có ý nghĩa.
martin clayton

18

Hãy bắt đầu dễ dàng với Nhà khai thác tàu vũ trụ .

$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 ++ không thực hiện trả về 3 giá trị cho các số. Nếu bộ nhớ phục vụ các hàm comapre String là trả về 3 giá trị duy nhất mà tôi biết trong toàn bộ ngôn ngữ STL. AFAIK Python không có so sánh số 3 trả về. Java cũng không có số trả về 3 số cụ thể.
JJ

7
Điều đáng nói là những gì rất hữu ích về các toán tử so sánh -1/0/1, vì không phải ai cũng có thể biết: bạn có thể xâu chuỗi chúng lại với toán tử hoặc toán tử để thực hiện chính / phụ / v.v. các loại. Vì vậy, ($a->lname cmp $b->lname) || ($a->fname cmp $b->fname)sắp xếp mọi người theo họ của họ, nhưng nếu hai người có cùng họ thì họ sẽ được đặt theo tên của họ.
hobbs

@JJ Python có so sánh 3 giá trị: cmp () >>> print (cmp (5,7), cmp (6,6), cmp (7,5)) (-1, 0, 1)
bukzor

18

Đây là một câu trả lời meta, nhưng Mẹo Perl tài liệu lưu trữ chứa tất cả các loại thủ thuật thú vị có thể được thực hiện với Perl. Lưu trữ các lời khuyên trước đây là trực tuyến để duyệt và có thể được đăng ký thông qua danh sách gửi thư hoặc nguồn cấp dữ liệu nguyên tử.

Một số mẹo ưa thích của tôi bao gồm xây dựng các tệp thực thi với PAR , sử dụng autodie để tự động đưa ra các ngoại lệ và sử dụng các cấu trúc chuyển đổikết hợp thông minh trong Perl 5.10.

Tiết lộ: Tôi là một trong những tác giả và người duy trì Mẹo Perl, vì vậy tôi rõ ràng nghĩ rất cao về họ. ;)


2
Đây có lẽ là một trong những ngôn ngữ được ghi chép tốt nhất hiện có và đặt mẫu cho các công cụ tìm kiếm tài liệu. Rằng danh sách trong câu hỏi này có lẽ không cần thiết như đối với các ngôn ngữ khác.
Axeman

1
autodie trông rất đẹp.
j_random_hacker

18

bản đồ - không chỉ bởi vì nó làm cho mã của ai đó biểu cảm hơn, mà bởi vì nó cho tôi một động lực để đọc thêm một chút về "lập trình chức năng" này.


15

Mệnh đề tiếp tục trên các vòng lặp. Nó sẽ được thực hiện ở dưới cùng của mỗi vòng lặp, ngay cả những vòng tiếp theo.

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

Phiếu bầu của tôi sẽ dành cho các nhóm (? {}) Và (?? {}) trong các biểu thức chính quy của Perl. Mã đầu tiên thực thi mã Perl, bỏ qua giá trị trả về, mã thứ hai thực thi mã, sử dụng giá trị trả về làm biểu thức chính quy.


perl đã phát minh ra rất nhiều phần mở rộng regex mà các chương trình khác hiện nay thường sử dụng pcre (perl tương thích regex) thay vì ngôn ngữ regex ban đầu.
Giây

Đọc bài giới thiệu nhỏ ở đây perldoc.perl.org/ Lời :-D
JJ

Perl thực sự có (theo như tôi biết), dẫn đầu gói, khi nói đến regexps.
Brad Gilbert

Điều này, theo như tôi biết, vẫn đang thử nghiệm và có thể không hoạt động theo cách tương tự trong Perls tương lai. Không phải nói rằng nó không hữu ích, nhưng phiên bản có thể sử dụng an toàn hơn một chút có thể được tìm thấy trong cờ s /// của lệnh / e: s/(pattern)/reverse($1);/ge;# đảo ngược tất cả patterns.
Chris Lutz

@Chris Lutz, @Leon Timmerman: Lưu ý rằng hai cấu trúc đó hiện đang được đăng ký lại. Cũng lưu ý rằng nhu cầu thứ hai không còn được sử dụng để thực hiện các mẫu đệ quy, bây giờ chúng ta có thể lặp lại trên các nhóm chụp. @Brad Gilbert: Điều đó đúng, mặc dù PCRE thực hiện tốt công việc theo dõi chúng tôi; một lĩnh vực xuất sắc của regex nơi Perl hoàn toàn không bị cản trở là quyền truy cập vào các thuộc tính Unicode; thấy phân phối unitrio của tôi uninames, unicharsvà đặc biệt là unipropsđể xem chỉ là một phần của những gì tôi có ý nghĩa.
tchrist

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

neo \ G. Trời nóng quá .


3
... Và nó chỉ ra vị trí kết thúc của trận đấu trước.
Dave Sherohman

1
Nhưng bạn phải gọi regex của bạn trong bối cảnh vô hướng.
davidnicol

@davidnicol: Đoạn mã trên hoạt động. Bạn có thể làm rõ những gì bạn có ý nghĩa?
JJ

13

Nhà m//điều hành có một số trường hợp đặc biệt tối nghĩa:

  • Nếu bạn sử dụng ?làm dấu phân cách, nó chỉ khớp một lần trừ khi bạn gọi reset.
  • Nếu bạn sử dụng 'như dấu phân cách thì mẫu không được nội suy.
  • Nếu mẫu trống, nó sử dụng mẫu từ trận đấu thành công cuối cùng.

2
Đây là giống như gotchas ẩn hơn các tính năng ẩn! Tôi không biết ai thích chúng. Một chủ đề trên p5p một thời gian trước đã thảo luận về tính hữu ích của cờ m / $ foo / r giả định, trong đó / r có nghĩa là không có nội suy (chữ cái không quan trọng) vì không ai có thể nhớ điều trích dẫn duy nhất.
dland

2
@dland: Đồng ý; Tôi gọi các tính năng sai này và sẽ không bao giờ sử dụng chúng trong mã sản xuất.
Michael Carman

7
Tôi không thể tưởng tượng một lập trình viên Perl không thể nhớ (hoặc thậm chí đoán) rằng các trích dẫn duy nhất không có nội suy. Việc sử dụng nó với ngữ nghĩa này gần như là phổ biến trong ngôn ngữ mà tôi mong muốn điều này sẽ trở nên như vậy ...
- Tái lập lại

và nếu mẫu trống và trận đấu thành công cuối cùng được biên dịch với công cụ sửa đổi / o, từ đó mẫu sẽ bị kẹt trên mẫu đó.
davidnicol

1
Tôi nghĩ rằng hành vi mẫu trống đã bị phản đối. Chủ yếu là vì một mẫu như m / $ foo / trở thành một lỗi khó chịu khi $ foo trống.
Matthew S

12

Toán tử kim cương tập tin null <>có vị trí của nó trong việc xây dựng các công cụ dòng lệnh. Nó hoạt động như <FH>đọc từ một tay cầm, ngoại trừ việc nó kỳ diệu chọn bất cứ thứ gì được tìm thấy đầu tiên: tên tệp dòng lệnh hoặc STDIN. Lấy từ perlop:

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

4
Nó cũng tuân theo ngữ nghĩa UNIX của việc sử dụng "-" có nghĩa là "đọc từ stdin. Vì vậy, bạn có thể làm perl myscript.pl file1.txt - file2.txtvà perl sẽ xử lý tệp đầu tiên, sau đó là stdin, sau đó là tệp thứ hai.
Ryan C. Thompson

Bạn có thể overloadcác <>nhà khai thác trên các đối tượng của riêng bạn ( <$var>) để làm việc như một iterator. Tuy nhiên nó không hoạt động như bạn có thể mong đợi trong bối cảnh danh sách.
heo

11

Các khối mã đặc biệt như BEGIN, CHECKEND. Họ đến từ Awk, nhưng hoạt động khác nhau ở Perl, vì nó không dựa trên hồ sơ.

Các BEGINkhối có thể được sử dụng để xác định một số mã cho giai đoạn phân tích; nó cũng được thực thi khi bạn thực hiện kiểm tra cú pháp và biến perl -c. Ví dụ: để tải các biến cấu hình:

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

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

đổi tên data.txt.part thành data.txt mà không phải lặp lại.


10

Một chút tối nghĩa là "toán tử" tilde-tilde buộc bối cảnh vô hướng.

print ~~ localtime;

giống như

print scalar localtime;

và khác với

print localtime;

5
Điều này đặc biệt khó hiểu vì perl5.10.0 cũng giới thiệu "toán tử kết hợp thông minh" ~~, có thể thực hiện khớp regex, có thể xem liệu một mục có trong một mảng hay không.
moritz

Điều đó không tối nghĩa, điều đó bị che khuất (và hữu ích cho golf và JAPH).
Michael Carman

Điều này LAF không đúng! ~ ~ không an toàn trên tài liệu tham khảo! Nó xâu chuỗi chúng.
Leon Timmermans

Vâng, vâng. Chuỗi hóa là những gì xảy ra với các tham chiếu khi buộc vào bối cảnh vô hướng. Làm thế nào mà làm cho "~ ~ buộc vô hướng bối cảnh" không chính xác?
Dave Sherohman

3
@Nomad Dervish: Bối cảnh vô hướng / = chuỗi hóa. ví dụ: "$ n = @a" là bối cảnh vô hướng. "$ s = qq '@ a'" là chuỗi. Đối với các tham chiếu, "$ ref1 = $ ref2" là bối cảnh vô hướng, nhưng không xâu chuỗi.
Michael Carman


9

"Chế độ tuyệt vọng" của các cấu trúc điều khiển vòng lặp của Perl khiến chúng tìm kiếm ngăn xếp để tìm nhãn phù hợp cho phép một số hành vi tò mò mà Test :: More tận dụng, tốt hơn hoặc xấu hơn.

SKIP: {
    skip() if $something;

    print "Never printed";
}

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

Có tệp .pmc ít được biết đến. "sử dụng Foo" sẽ tìm kiếm Foo.pmc trong @INC trước Foo.pm. Điều này được dự định để cho phép mã byte được biên dịch được tải trước tiên, nhưng Module :: Compile tận dụng lợi thế này để lưu trữ các mô-đun được lọc nguồn để có thời gian tải nhanh hơn và gỡ lỗi dễ dàng hơn.

Khả năng biến cảnh báo thành lỗi.

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

Đó là những gì tôi có thể nghĩ ra khỏi đỉnh đầu của tôi đã không được đề cập.


9

Người điều khiển dê *:

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

hoặc là

sub foo {
    return @_;
}

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

Nó hoạt động vì gán danh sách trong ngữ cảnh vô hướng mang lại số lượng phần tử trong danh sách được gán.

* Lưu ý, không thực sự là một nhà điều hành


Đó là "nhà điều hành" đẹp nhất (tốt nhất, ít nhất) từ trước đến nay.
Chris Lutz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.