Каковы некоторые действительно полезные, но эзотерические языковые функции в Perl, которые вы действительно смогли использовать для полезной работы?
Руководство:
(Все они из Corion answer)
Операторы:
++
и унарные -
работают со строками.m//
Цитаты конструкций:
Синтаксис и имена:
Модули, Pragmas и параметры командной строки:
overload::constant
Переменные
Циклы и управление потоком:
Регулярные выражения:
Другие функции:
DATA
eof
dbmopen
Другие трюки и мета-ответы:
См. также:
Оператор триггера полезен для пропуски первой итерации при прокрутке записей (обычно строк), возвращаемых дескриптором файла, без использования переменной флага:
while(<$fh>)
{
next if 1..1; # skip first record
...
}
Запустите perldoc perlop
и найдите "флип-флоп" для получения дополнительной информации и примеров.
В Perl существует много неочевидных функций.
Например, знаете ли вы, что после сигилы может быть пробел?
$ perl -wle 'my $x = 3; print $ x'
3
Или что вы можете указывать числовые имена субтитров, если вы используете символические ссылки?
$ perl -lwe '*4 = sub { print "yes" }; 4->()'
yes
Также существует квази-оператор "bool", который возвращает 1 для истинных выражений и пустую строку для false:
$ 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/
Добавить поддержку сжатых файлов с помощью 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;
(кавычки вокруг $_ необходимы для обработки имен файлов с метасимволами оболочки)
Теперь функция <>
распакует любые файлы @ARGV
, которые заканчиваются на ".gz" или ".Z":
while (<>) {
print;
}
|
в замену.
Одна из моих любимых функций в 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; # 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,
Пол
Операторы ++ и унарные - работают не только на числах, но и на строках.
my $_ = "a"
print -$_
печатает -a
print ++$_
печатает b
$_ = 'z'
print ++$_
печатает aa
--
не работает на строках.
Поскольку Perl имеет почти все "эзотерические" части из других списков, я расскажу вам одну вещь, которую Perl не может:
Единственное, что Perl не может сделать, это иметь произвольные URL-адреса в вашем коде, потому что оператор //
используется для регулярных выражений.
На всякий случай вам не было очевидно, какие функции предлагает Perl, здесь есть выборочный список, возможно, не полностью очевидных записей:
Переносимость и стандартность - Вероятно, больше компьютеров с Perl, чем с компилятором C
Класс манипуляции файлами/путями - Файл:: Найти работу в еще более операционных системах чем .NET делает
Цитаты для списков с разделителями пробелов и строки - 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
Autovivification. AFAIK нет другого языка.
Просто процитировать почти любую странную строку в 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: интерпретированная цитата; обрабатывает переменные и escape-символы. Отлично подходит для строк, которые вам нужно процитировать:
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: очень полезный оператор цитаты. Включает в список цитированный набор пробельных разделенных слов. Отлично подходит для заполнения данных в unit test.
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//.
Не очень скрыт, но много раз каждый день программисты на Perl не знают о CPAN. Это особенно относится к людям, которые не являются программистами на полный рабочий день или не работают на Perl в полном объеме.
Оператор "for" можно использовать так же, как "с" используется в Pascal:
for ($item)
{
s/ / /g;
s/<.*?>/ /g;
$_ = join(" ", split(" ", $_));
}
Вы можете применить последовательность операций s///и т.д. к одной и той же переменной без необходимости повторять имя переменной.
ПРИМЕЧАНИЕ. Неразрывное пространство выше (& nbsp;) скрыло Unicode в нем, чтобы обойти Markdown. Не копируйте его:)
Возможность анализировать данные, непосредственно вставленные в блок DATA. Не нужно сохранять в тестовый файл, который нужно открыть в программе или аналогично. Например:
my @lines = <DATA>;
for (@lines) {
print if /bad/;
}
__DATA__
some good data
some bad data
more good data
more good data
Оператор quoteword - одна из моих любимых вещей. Для сравнения:
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.
for (<a list of stuff>) { ... }
Проверка тонкости. При включенной проверке taint perl умрет (или предупреждает, -t
), если вы попытаетесь передать испорченные данные (грубо говоря, данные извне программы) в небезопасную функцию (открытие файла, запуск внешней команды и т.д.).). Это очень полезно при написании скриптов setuid или CGI или чего-либо, где script имеет больше привилегий, чем тот, кто его подает.
Магический переход. goto &sub
выполняет оптимизированный хвостовой вызов.
Отладчик.
use strict
и use warnings
. Это может спасти вас от множества опечаток.
Я бы сказал, что способность расширять язык, создавая операции псевдоблока, - это один.
Вы объявляете прототип субподачи, указывающий, что он сначала берет ссылку на код:
sub do_stuff_with_a_hash (&\%) {
my ( $block_of_code, $hash_ref ) = @_;
while ( my ( $k, $v ) = each %$hash_ref ) {
$block_of_code->( $k, $v );
}
}
Затем вы можете вызвать его в теле так
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
будет просто сканировать как "переменные", так и константы, создавать их и подставлять их по мере необходимости.
Опять же, исходные фильтры могут быть беспорядочными, но мощными. Но они могут испортить отладчику что-то ужасное - и даже предупреждения могут быть напечатаны с неправильными номерами строк. Я перестал использовать Damian Switch, потому что отладчик потерял бы все возможности сказать мне, где я на самом деле был. Но я обнаружил, что вы можете минимизировать ущерб, изменяя небольшие разделы кода, сохраняя их в одной строке.
Это довольно часто делается, но это не все так очевидно. Здесь грабитель, который поросенок спит на старый.
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
sub:
overload::constant
integer => sub {
my $lit = shift;
return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit
};
это будет означать, что каждое целое число более 2 миллиардов в вызывающих пакетах будет изменено на объект Math::BigInt
. (См. overload:: constant).
Пока мы на нем. Perl позволяет разбивать большие числа на группы из трех цифр и получать из него только синтаксическое целое число. Примечание 2_000_000_000
выше для 2 миллиардов.
Двоичный "x" - это оператор повторения:
print '-' x 80; # print row of dashes
Он также работает со списками:
print for (1, 4, 9) x 3; # print 149149149
На основе того, как переключатели "-n"
и "-p"
реализованы в Perl 5, вы можете написать, казалось бы, неправильную программу, включая }{
:
ls |perl -lne 'print $_; }{ print "$. Files"'
который внутренне преобразуется в этот код:
LINE: while (defined($_ = <ARGV>)) {
print $_; }{ print "$. Files";
}
map - не только потому, что он делает один код более выразительным, а потому, что он дал мне импульс прочитать немного больше об этом "функциональном программировании".
Это мета-ответ, но Perl Tips архивы содержат всевозможные интересные трюки, которые можно сделать с помощью Perl. Архив предыдущих советов доступен в режиме онлайн для просмотра и может быть подписан через список рассылки или подачу атома.
Некоторые из моих любимых советов включают создание исполняемых файлов с PAR, используя autodie для автоматического исключения исключений и использования switch и smart-match в Perl 5.10.
Раскрытие информации: Я являюсь одним из авторов и сторонников Perl-советов, поэтому я, очевидно, очень высоко ценю их.;)
Легко начать с Оператор космического корабля.
$a = 5 <=> 7; # $a is set to -1
$a = 7 <=> 5; # $a is set to 1
$a = 6 <=> 6; # $a is set to 0
Предложение 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";
}
Мое голосование пойдет для групп (? {}) и (?? {}) в регулярных выражениях Perl. Первый выполняет код Perl, игнорируя возвращаемое значение, второй выполняет код, используя возвращаемое значение как регулярное выражение.
while(/\G(\b\w*\b)/g) {
print "$1\n";
}
the\G anchor. Он горячий.
Оператор m//
имеет некоторые неясные частные случаи:
?
в качестве разделителя, он соответствует только одному, если вы не вызываете reset
.'
в качестве разделителя, шаблон не интерполируется.Нулевой дескриптор файла алмазный оператор <>
имеет свое место в создании инструментов командной строки. Он действует как <FH>
для чтения из дескриптора, за исключением того, что он волшебным образом выбирает то, что было найдено первым: имена файлов командной строки или STDIN. Взято из perlop:
while (<>) {
... # code for each line
}
perl myscript.pl file1.txt - file2.txt
, и perl обработает первый файл, затем stdin, а затем второй файл.
overload
оператор <>
для своих собственных объектов ( <$var>
), чтобы работать как итератор. Однако это не работает, как вы могли ожидать в контексте списка.
rename("$_.part", $_) for "data.txt";
переименовывает data.txt.part в data.txt, не повторяя себя.
Специальные кодовые блоки, такие как BEGIN
, CHECK
и END
. Они происходят из Awk, но работают по-разному в Perl, потому что они не основаны на записи.
Блок BEGIN
может использоваться для указания некоторого кода для фазы синтаксического анализа; он также выполняется, когда вы выполняете проверку синтаксиса и переменной perl -c
. Например, чтобы загрузить переменные конфигурации:
BEGIN {
eval {
require 'config.local.pl';
};
if ($@) {
require 'config.default.pl';
}
}
UNITCHECK
. ☺
Немного неясным является "оператор" тильд-тильды, который заставляет скалярный контекст.
print ~~ localtime;
совпадает с
print scalar localtime;
и отличается от
print localtime;
~~
, который может выполнять сопоставление с регулярным выражением, может посмотреть, содержится ли элемент в массиве и так далее.
В разделителе входных записей можно указать ссылку на число для чтения записей фиксированной длины:
$/ = \3; print $_,"\n" while <>; # output three chars on each line
Оператор goatse *
:
$_ = "foo bar";
my $count =()= /[aeiou]/g; #3
или
sub foo {
return @_;
}
$count =()= foo(qw/a b c d/); #4
Это работает, потому что назначение списка в скалярном контексте дает количество элементов в списке, который назначается.
*
Обратите внимание, что это не оператор
&~
«оператора».
tie, интерфейс привязки переменных.
Вы можете использовать @{[...]}, чтобы получить интерполированный результат сложных выражений perl
$a = 3;
$b = 4;
print "$a * $b = @{[$a * $b]}";
Отпечатки: 3 * 4 = 12
Этот не особенно полезен, но он чрезвычайно эзотеричен. Я наткнулся на это, копаясь в парсере Perl.
До того, как появился POD, у perl4 был трюк, позволяющий вставлять man-страницу, как nroff, прямо в вашу программу, чтобы она не потерялась. perl4 использовал программу, называемую wrapman (для некоторых деталей см. страницу Pink Camel на стр. 319), чтобы умело внедрить man-страницу nroff в ваш script.
Он работал, говоря nroff игнорировать весь код, а затем помещал мясо man-страницы после тега END, который сообщает 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...
Детали магии roff убегают от меня, но вы заметите, что команды roff представляют собой строки или числа в пустотном контексте. Обычно константа в пустоте создает предупреждение. В op.c
есть специальные исключения, чтобы разрешить строки контекста void, которые начинаются с определенных команд roff.
/* perl4 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;
Это означает, что '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;
И что вы знаете, 2 while condition
предупреждает!
Я не знаю, насколько это эзотерично, но одним из моих фаворитов является хэш-фрагмент. Я использую его для всех вещей. Например, чтобы слить два хэша:
my %number_for = (one => 1, two => 2, three => 3); my %your_numbers = (two => 2, four => 4, six => 6); @number_for{keys %your_numbers} = values %your_numbers; print sort values %number_for; # 12346
use diagnostics;
Если вы начинаете работать с Perl и никогда раньше этого не делали, этот модуль сэкономит вам массу времени и хлопот. Для почти каждого основного сообщения об ошибке, которое вы можете получить, этот модуль даст вам подробное объяснение, почему ваш код ломается, включая некоторые полезные советы о том, как его исправить. Например:
use strict;
use diagnostics;
$var = "foo";
дает вам это полезное сообщение:
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 " };
};
вы получите этот большой, полезный фрагмент текста:
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 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.
sub load_file
{
local(@ARGV, $/) = shift;
<>;
}
и версию, которая возвращает массив по мере необходимости:
sub load_file
{
local @ARGV = shift;
local $/ = wantarray? $/: undef;
<>;
}
@Schwern упомянул о том, что в предупреждениях были допущены ошибки, локализуя $SIG{__WARN__}
. Вы также можете сделать это (лексически) с помощью use warnings FATAL => "all";
. См. perldoc lexwarn
.
В этой заметке, поскольку Perl 5.12, вы можете сказать perldoc foo
вместо полного perldoc perlfoo
. В заключение!:)
($ x, $y) = ($ y, $x) - это то, что заставило меня хотеть изучить Perl.
Конструктор списка 1.99 или 'a'.. 'zz' тоже очень приятный.
Также существует $[переменная, которая решает, по какому индексу начинается массив. Значение по умолчанию равно 0, поэтому массив начинается с 0. Установив
$[=1;
Вы можете заставить Perl вести себя как AWK (или Fortran), если вы действительно этого хотите.
Этот однострочный рисунок иллюстрирует, как использовать glob для генерации всех словосочетаний алфавита (A, T, C и G → DNA) для слов определенной длины (4):
perl -MData::Dumper -e '@CONV = glob( "{A,T,C,G}" x 4 ); print Dumper( \@CONV )'
Один полезный составной оператор для условного добавления строк или списков в другие списки - это оператор x!!
:
print 'the meaning of ', join ' ' =>
'life,' x!! $self->alive,
'the universe,' x!! ($location ~~ Universe),
('and', 'everything.') x!! 42; # this is added as a list
этот оператор допускает обратный синтаксис, аналогичный
do_something() if test();
Schwartzian Transform - это метод, который позволяет эффективно сортировать по вычисленному вторичному индексу. Скажем, что вы хотели отсортировать список строк по их сумме md5. Нижеприведенные комментарии лучше всего читать назад (что порядок, который я всегда в конечном итоге пишу их):
my @strings = ('one', 'two', 'three', 'four');
my $md5sorted_strings =
map { $_->[0] } # 4) map back to the original value
sort { $a->[1] cmp $b->[1] } # 3) sort by the correct element of the list
map { [$_, md5sum_func($_)] } # 2) create a list of anonymous lists
@strings # 1) take strings
Таким образом, вам нужно выполнить только дорогостоящее вычисление md5 N раз, а не N log N раз.
Используйте lvalues, чтобы сделать ваш код действительно запутанным:
my $foo = undef ;
sub bar:lvalue{ return $foo ;}
# Then later
bar = 5 ;
print bar ;
Хорошо. Вот еще один. Динамическое масштабирование. О нем немного говорили в другом посте, но я не видел его здесь по скрытым функциям.
Динамическое масштабирование, как Autovivification, имеет очень ограниченное количество языков, которые его используют. Perl и Common Lisp - это единственные, которые я знаю об использовании Dynamic Scoping.
Как насчет возможности использования
my @symbols = map { +{ 'key' => $_ } } @things;
чтобы сгенерировать массив hashrefs из массива - + перед хэш файлом устраняет неоднозначность блока, поэтому интерпретатор знает, что это hashref, а не блок кода. Высокий.
(Спасибо Дэйву Дойлу за объяснение этого мне на последней встрече в Торонто Перлмонджерс.)
Core IO::Handle
. Самое главное для меня - это то, что он позволяет autoflush на дескрипторах файлов. Пример:
use IO::Handle;
$log->autoflush(1);
IO::Handle
, вы знаете.
Безопасные отсеки.
С помощью модуля Safe вы можете создать собственную среду в стиле песочницы, используя только перл. Затем вы сможете загружать Perl-скрипты в песочницу.
С уважением,
Вы можете использовать разные кавычки на HEREDOCS для получения разных поведений.
my $interpolation = "We will interpolated variables";
print <<"END";
With double quotes, $interpolation, just like normal HEREDOCS.
END
print <<'END';
With single quotes, the variable $foo will *not* be interpolated.
(You have probably seen this in other languages.)
END
## this is the fun and "hidden" one
my $shell_output = <<`END`;
echo With backticks, these commands will be executed in shell.
echo The output is returned.
ls | wc -l
END
print "shell output: $shell_output\n";
use re debug
Doc для повторной отладки
и
perl -MO=Concise[,OPTIONS]
Док в сжатом
Помимо гибкости, выразительности и возможности программирования в стиле C, Pascal, Python и других языков, существует несколько команд командной строки pragmas, которые делают Perl моим языком 'goto' для начального kanoodling по алгоритму, регулярному выражению или которые необходимо решить. Эти два являются уникальными для Perl, я считаю, и являются одними из моих фаворитов.
use re debug
:
Большинство современных ароматов регулярных выражений обязаны их текущей форме и функции Perl. Хотя существует много форм Perl регулярного выражения, которые не могут быть выражены на других языках, почти нет форм выражения других языков, которые не могут быть выражены в Perl. Кроме того, Perl имеет замечательный встроенный отладчик регулярных выражений, чтобы показать, как механизм регулярных выражений интерпретирует ваше регулярное выражение и сопоставляется с целевой строкой.
Пример: Недавно я пытался написать простую процедуру CSV. (Да, да, я знаю, мне следовало использовать Text:: CSV...), но значения CSV не были процитированы и просты,
Мое первое взятие было /^(^(?:(.*?),){$i}/
, чтобы извлечь запись я в n CSV-записи. Это отлично работает - за исключением последней записи или n из n. Я мог видеть это без отладчика.
Далее я попробовал /^(?:(.*?),|$){$i}/
Это не сработало, и я не мог сразу понять, почему. Я думал, что я говорю (.*?)
, за которым следует запятая или EOL. Затем я добавил use re debug
в верхней части небольшого теста script. Ах, да, изменение между ,|$
не интерпретировалось таким образом; его интерпретировали как ((.*?),) | ($)
- не то, что я хотел.
Требуется новая группировка. Поэтому я пришел к рабочему /^(?:(.*?)(?:,|$)){$i}/
. В то время как я был в отладчике регулярных выражений, я был удивлен, сколько циклов потребовалось для соответствия к концу строки. Это термин .*?
, который довольно неоднозначен и требует чрезмерного возврата для удовлетворения. Итак, я попробовал /^(?:(?:^|,)([^,]*)){$i}/
Это делает две вещи: 1) уменьшает обратную трассировку из-за жадного соответствия всех, кроме запятой. 2) разрешил оптимизатору регулярных выражений использовать только одно изменение в первом поле. Используя Benchmark, это на 35% быстрее, чем первое регулярное выражение. Отладчик регулярных выражений замечательный, и его мало используют.
perl -MO=Concise[,OPTIONS]
:
Структуры B и Concise являются огромными инструментами, чтобы увидеть, как Perl интерпретирует ваш шедевр. Использование -MO=Concise
печатает результат перевода интерпретатора Perl вашего исходного кода. Есть много вариантов Concise и в B, вы можете написать собственную презентацию OP-кодов.
Как в этом сообщении, вы можете использовать Concise для сравнения различных структур кода. Вы можете чередовать исходные строки с кодами OP, которые генерируют эти строки. Проверьте это.
Существует более мощный способ проверки программ на синтаксические ошибки:
perl -w -MO=Lint,no-context myscript.pl
Самое главное, что он может сделать, это сообщить об ошибках "неустойчивой подпрограммы".
use Quantum::Superpositions;
if ($x == any($a, $b, $c)) { ... }
Мне лично нравится модификатор /e для операции s///:
while(<>) {
s/(\w{0,4})/reverse($1);/e; # reverses all words between 0 and 4 letters
print;
}
Input:
This is a test of regular expressions
^D
Выход (я думаю):
sihT si a tset fo regular expressions
Очень поздно для вечеринки, но: атрибуты.
Атрибуты в основном позволяют определить произвольный код для связи с объявлением переменной или подпрограммы. Лучший способ их использования - Attribute::Handlers; это упрощает определение атрибутов (в терминах, что еще, атрибуты!).
Я сделал презентацию об их использовании, чтобы декларативно собрать подключаемый класс и его плагины в YAPC:: 2006, в Интернете здесь. Это довольно уникальная функция.
Вы можете заменить разделитель в регулярных выражениях и строках практически любым другим. Это особенно полезно для "отклонения синдрома зубочистки", приведенного здесь:
$url =~ /http:\/\/www\.stackoverflow\.com\//;
Вы можете устранить большую часть обратного удара, изменив разделитель. /bar/
является сокращением для m/bar/
, которое совпадает с m!bar!
.
$url =~ m!http://www\.stackoverflow\.com/!;
Вы можете даже использовать сбалансированные разделители типа {} и []. Я лично их люблю. q{foo}
совпадает с 'foo'
.
$code = q{
if( this is awesome ) {
print "Look ma, no escaping!";
}
};
Чтобы запутать ваших друзей (и ваш ярлык синтаксиса), попробуйте следующее:
$string = qq'You owe me $1,000 dollars!';
{}
(и друзей) , как кавычки, Perl будет балансировать разделители.
Моя любимая полускрытая функция Perl - это функция eof
. Вот пример, очень похожий непосредственно из perldoc -f eof
, который показывает, как вы можете легко использовать его для reset имени файла и $.
(номер текущей строки) для нескольких файлов, загруженных в командной строке:
while (<>) {
print "$ARGV:$.\t$_";
}
continue {
close ARGV if eof
}
Функция, которая мне больше всего нравится, - это модификаторы выражений.
Не знаю, сколько раз я хотел сделать:
say 'This will output' if 1;
say 'This will not output' unless 1;
say 'Will say this 3 times. The first Time: '.$_ for 1..3;
на других языках. и т.д...
"и т.д." напомнил мне еще одну функцию 5.12, оператора Яда Яда.
Это замечательно, когда вы просто хотите владельца места.
sub something_really_important_to_implement_later {
...
}
Проверьте это: Perl Docs на Яда Яда Оператор.
Вы можете развернуть вызовы функций в строке, например:
print my $foo = "foo @{[scalar(localtime)]} bar";
foo Среда 26 мая 15:50:30 2010 бар
Возможность использовать хэш как видимый фильтр в цикле. Мне еще нужно увидеть что-то совершенно приятное на другом языке. Например, я не смог дублировать это в python.
Например, я хочу напечатать строку, если она не была замечена раньше.
my %seen;
for (<LINE>) {
print $_ unless $seen{$_}++;
}
Новая опция -E в командной строке:
> perl -e "say 'hello"" # does not work
String found where operator expected at -e line 1, near "say 'hello'"
(Do you need to predeclare say?)
syntax error at -e line 1, near "say 'hello'"
Execution of -e aborted due to compilation errors.
> perl -E "say 'hello'"
hello
Две вещи, которые хорошо работают вместе: IO обрабатывает встроенные строки и использует прототипы функций, чтобы вы могли писать свои собственные функции с синтаксисом grep/map-like.
sub with_output_to_string(&) { # allows compiler to accept "yoursub {}" syntax.
my $function = shift;
my $string = '';
my $handle = IO::Handle->new();
open($handle, '>', \$string) || die $!; # IO handle on a plain scalar string ref
my $old_handle = select $handle;
eval { $function->() };
select $old_handle;
die $@ if $@;
return $string;
}
my $greeting = with_output_to_string {
print "Hello, world!";
};
print $greeting, "\n";
Ниже приведены краткие, но более значимые, чем "~~", поскольку они указывают, что возвращается, и нет путаницы с оператором smart match:
print "".localtime; # Request a string
print 0+@array; # Request a number
Axeman напомнил мне, насколько легко переносить некоторые из встроенных функций.
До Perl 5.10. В Perl не было красивой печати (скажем), такой как Python.
Итак, в вашей локальной программе вы можете сделать что-то вроде:
sub print {
print @_, "\n";
}
или добавить некоторые отладки.
sub print {
exists $ENV{DEVELOPER} ?
print Dumper(@_) :
print @_;
}
print @_, "\n"
(обратите внимание на запятую) сохранит контекст.
В следующий раз, когда вы окажетесь на вечеринке, вытащите этот лайнер в оболочку bash, и женщины будут роивать вас, и ваши друзья будут поклоняться вам:
найти. -name "*.txt" | xargs perl -pi -e 's/1: (\ S +)/uc ($ 1)/ge'
Обработать все *.txt файлы и выполнить поиск и замену на месте с помощью регулярного выражения perl. Он преобразует текст после "1:" в верхний регистр и удаляет "1:". Использует модификатор Perl 'e' для обработки второй части поискового/замещающего регулярного выражения как исполняемого кода. Мгновенная однострочная система шаблонов. Использование xargs позволяет обрабатывать огромное количество файлов без использования ограничения длины строки командной строки bash.
Добавьте один для функций unpack() и pack(), которые являются большими, если вам нужно импортировать и/или экспортировать данные в формате, который используется другими программами.
Конечно, в наши дни большинство программ позволят вам экспортировать данные в XML, а многие распространенные форматы документов имеют связанные с ними модули Perl, написанные для них. Но это одна из тех функций, которые невероятно полезны, когда вам это нужно, и pack()/unpack(), вероятно, являются причиной того, что люди смогли записать модули CPAN для столь многих проприетарных форматов данных.
Использование хешей (где уникальные ключи) для получения уникальных элементов списка:
my %unique = map { $_ => 1 } @list;
my @unique = keys %unique;
Интерполяция регулярных выражений матча. Полезным приложением этого является сопоставление в черном списке. Без использования интерполяции оно написано так:
#detecting blacklist words in the current line
/foo|bar|baz/;
Вместо этого можно записать
@blacklistWords = ("foo", "bar", "baz");
$anyOfBlacklist = join "|", (@blacklistWords);
/$anyOfBlacklist/;
Это более подробный, но позволяет населению из файла данных. Также, если список поддерживается в источнике по какой-либо причине, легче поддерживать массив, а затем RegExp.
Выражение defined &DB::DB
возвращает true, если программа запущена из отладчика.
Возможно, вы можете сделать это, чтобы сохранить память:
@is_month{qw(jan feb mar apr may jun jul aug sep oct nov dec)} = undef;
print "It a month" if exists $is_month{lc $mon};
но он этого не делает. Perl по-прежнему присваивает каждому скалярному значению другое скалярное значение. Devel::Peek показывает это. PVHV
- хэш. Elt
- это ключ, а SV
- его значение. Обратите внимание, что каждый SV имеет другой адрес памяти, указывающий, что он не используется.
Dump \%is_month, 12;
SV = RV(0x81c1bc) at 0x81c1b0
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x812480
SV = PVHV(0x80917c) at 0x812480
REFCNT = 2
FLAGS = (SHAREKEYS)
ARRAY = 0x206f20 (0:8, 1:4, 2:4)
hash quality = 101.2%
KEYS = 12
FILL = 8
MAX = 15
RITER = -1
EITER = 0x0
Elt "feb" HASH = 0xeb0d8580
SV = NULL(0x0) at 0x804b40
REFCNT = 1
FLAGS = ()
Elt "may" HASH = 0xf2290c53
SV = NULL(0x0) at 0x812420
REFCNT = 1
FLAGS = ()
Сканер undef занимает столько же памяти, сколько целочисленный скаляр, поэтому вы можете попросить, чтобы просто назначили их всем 1 и избегайте ловушки забывания, чтобы проверить с помощью exists
.
my %is_month = map { $_ => 1 } qw(jan feb mar apr may jun jul aug sep oct nov dec);
print "It a month" if $is_month{lc $mon});
Я немного опаздываю на вечеринку, но голосование за встроенную связанную хэш-функцию dbmopen()
- это очень помогло мне. Это не совсем база данных, но если вам нужно сохранить данные на диск, это уберет много проблем и Just Works. Это помогло мне начать работу, когда у меня не было базы данных, не понял Storable.pm, но я знал, что хочу продвинуться дальше чтения и записи в текстовые файлы.
B:: Deparse - Бэкэндер для Perl для создания Perl-кода. Не то, что вы использовали бы в своем ежедневном кодировании Perl, но может быть полезным в особых обстоятельствах.
Если вы сталкиваетесь с каким-то фрагментом кода, который запутан, или сложным выражением, передайте его через Deparse
. Полезно выяснить код JAPH или Perl, который используется в гольф.
$ perl -e '$"=$,;*{;qq{@{[(A..Z)[qq[0020191411140003]=~m[..]g]]}}}=*_=sub{print/::(.*)/};$\=$/;q<Just another Perl Hacker>->();'
Just another Perl Hacker
$ perl -MO=Deparse -e '$"=$,;*{;qq{@{[(A..Z)[qq[0020191411140003]=~m[..]g]]}}}=*_=sub{print/::(.*)/};$\=$/;q<Just another Perl Hacker>->();'
$" = $,;
*{"@{[('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')['0020191411140003' =~ /../g]];}";} = *_ = sub {
print /::(.*)/;
}
;
$\ = $/;
'Just another Perl Hacker'->();
-e syntax OK
Более полезным примером является использование deparse для выяснения кода, лежащего в основе coderef, который вы могли бы получить от другого модуля, или
use B::Deparse;
my $deparse = B::Deparse->new;
$code = $deparse->coderef2text($coderef);
print $code;
Мне нравится способ вставки элемента в любое место в массиве, например
= > Вставить $x в позицию $i в массиве @a
@a = ( 11, 22, 33, 44, 55, 66, 77 );
$x = 10;
$i = 3;
@a = ( @a[0..$i-1], $x, @a[$i..$#a] );
"теперь"
sub _now {
my ($now) = localtime() =~ /([:\d]{8})/;
return $now;
}
print _now(), "\n"; # 15:10:33
Perl отлично подходит как гибкий awk/sed.
Например, можно использовать простую замену для ls | xargs stat
, наивно сделанное как:
$ ls | perl -pe 'print "stat "' | sh
Это не работает, когда вход (имена файлов) имеет пробелы или специальные символы оболочки, такие как |$\
. Поэтому в выводе Perl часто требуются одинарные кавычки.
Одно из осложнений с вызовом perl через командную строку -ne
заключается в том, что оболочка получает первый кусок на вашем одном слое. Это часто приводит к мучительному побегу, чтобы удовлетворить его.
Одна скрытая функция, которую я использую все время \x27
, чтобы включить одну цитату вместо того, чтобы пытаться использовать экранирование оболочки '\''
Итак:
$ ls | perl -nle 'chomp; print "stat '\''$_'\''"' | sh
можно более безопасно записать:
$ ls | perl -pe 's/(.*)/stat \x27$1\x27/' | sh
Это не будет работать со смешными символами в именах файлов, даже цитируется так. Но это будет:
$ ls | perl -pe 's/\n/\0/' | xargs -0 stat
с использованием незакрытых блоков с redo
или другими управляющими словами для создания пользовательских конструкций циклов.
пересечь связанный список объектов, возвращающих первый метод ->can('print')
:
sub get_printer {
my $self = shift;
{$self->can('print') or $self = $self->next and redo}
}
$0 - это имя выполняемого perl script. Его можно использовать для получения контекста, из которого выполняется модуль.
# MyUsefulRoutines.pl
sub doSomethingUseful {
my @args = @_;
# ...
}
if ($0 =~ /MyUsefulRoutines.pl/) {
# someone is running perl MyUsefulRoutines.pl [args] from the command line
&doSomethingUseful (@ARGV);
} else {
# someone is calling require "MyUsefulRoutines.pl" from another script
1;
}
Эта идиома полезна для рассмотрения автономного script с некоторыми полезными подпрограммами в библиотеку, которая может быть импортирована в другие скрипты. Python имеет аналогичную функциональность с object.__name__ == "__main__"
идиомой.
Еще один...
Кэш Perl:
my $processed_input = $records || process_inputs($records_file);
На Elpeleg Open Source, Perl CMS http://www.web-app.net/
Отображение прогресса в script путем печати в той же строке:
$| = 1; # flush the buffer on the next output
for $i(1..100) {
print "Progress $i %\r"
}
@Corion - Простые URL-адреса в Perl? Конечно, вы можете даже в интерполированных строках. Единственный раз, когда это имеет значение, - это строка, которую вы фактически использовали в качестве регулярного выражения.
http://www.example.com
( http:
это метка, а //
делает оставь комментарий). Это то, что все имеют в виду.