Скрытые черты Perl?
Каковы некоторые действительно полезные, но эзотерические языковые функции в Perl, которые вы действительно смогли использовать для полезной работы?
Руководство:
- Попробуйте ограничить ответы на ядро Perl, а не CPAN
- Приведите пример и краткое описание
Скрытые функции также найдены на других языках. Скрытые функции:
(Все они из Corion answer)
- C
- Устройство Duff
- Переносимость и стандартность
- С#
- Цитаты для списков и строк с разделителями пробелов
- Простые пространства имен
- Java
- JavaScript
- Функции являются гражданами первого класса.
- Область и закрытие блока
- Вызов методов и аксессуаров косвенно через переменную
- Ruby
- Определение методов с помощью кода
- PHP
- Прорывная онлайн-документация
- Магические методы
- Символьные ссылки
- Python
- Обмен одной строкой
- Возможность заменить даже основные функции своей собственной функциональностью
Другие скрытые функции:
Операторы:
Цитаты конструкций:
Синтаксис и имена:
Модули, Pragmas и параметры командной строки:
Переменные
Циклы и управление потоком:
Регулярные выражения:
Другие функции:
Другие трюки и мета-ответы:
См. также:
Ответы
Ответ 1
Оператор триггера полезен для пропуски первой итерации при прокрутке записей (обычно строк), возвращаемых дескриптором файла, без использования переменной флага:
while(<$fh>)
{
next if 1..1; # skip first record
...
}
Запустите perldoc perlop
и найдите "флип-флоп" для получения дополнительной информации и примеров.
Ответ 2
В 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/
Ответ 3
Добавить поддержку сжатых файлов с помощью 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;
}
Ответ 4
Одна из моих любимых функций в 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,
Пол
Ответ 5
Операторы ++ и унарные - работают не только на числах, но и на строках.
my $_ = "a"
print -$_
печатает -a
print ++$_
печатает b
$_ = 'z'
print ++$_
печатает aa
Ответ 6
Поскольку Perl имеет почти все "эзотерические" части из других списков, я расскажу вам одну вещь, которую Perl не может:
Единственное, что Perl не может сделать, это иметь произвольные URL-адреса в вашем коде, потому что оператор //
используется для регулярных выражений.
На всякий случай вам не было очевидно, какие функции предлагает Perl, здесь есть выборочный список, возможно, не полностью очевидных записей:
Duff Device - в 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
Ответ 7
Autovivification. AFAIK нет другого языка.
Ответ 8
Просто процитировать почти любую странную строку в 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//.
Ответ 9
Оператор "for" можно использовать так же, как "с" используется в Pascal:
for ($item)
{
s/ / /g;
s/<.*?>/ /g;
$_ = join(" ", split(" ", $_));
}
Вы можете применить последовательность операций s///и т.д. к одной и той же переменной без необходимости повторять имя переменной.
ПРИМЕЧАНИЕ. Неразрывное пространство выше (& nbsp;) скрыло Unicode в нем, чтобы обойти Markdown. Не копируйте его:)
Ответ 10
Не очень скрыт, но много раз каждый день программисты на Perl не знают о CPAN. Это особенно относится к людям, которые не являются программистами на полный рабочий день или не работают на Perl в полном объеме.
Ответ 11
Оператор 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.
Ответ 12
Возможность анализировать данные, непосредственно вставленные в блок DATA. Не нужно сохранять в тестовый файл, который нужно открыть в программе или аналогично. Например:
my @lines = <DATA>;
for (@lines) {
print if /bad/;
}
__DATA__
some good data
some bad data
more good data
more good data
Ответ 13
Двоичный "x" - это оператор повторения:
print '-' x 80; # print row of dashes
Он также работает со списками:
print for (1, 4, 9) x 3; # print 149149149
Ответ 14
Новые операции с блоком
Я бы сказал, что способность расширять язык, создавая операции псевдоблока, - это один.
-
Вы объявляете прототип субподачи, указывающий, что он сначала берет ссылку на код:
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 миллиардов.
Ответ 15
Проверка тонкости. При включенной проверке taint perl умрет (или предупреждает, -t
), если вы попытаетесь передать испорченные данные (грубо говоря, данные извне программы) в небезопасную функцию (открытие файла, запуск внешней команды и т.д.).). Это очень полезно при написании скриптов setuid или CGI или чего-либо, где script имеет больше привилегий, чем тот, кто его подает.
Магический переход. goto &sub
выполняет оптимизированный хвостовой вызов.
Отладчик.
use strict
и use warnings
. Это может спасти вас от множества опечаток.
Ответ 16
На основе того, как переключатели "-n"
и "-p"
реализованы в Perl 5, вы можете написать, казалось бы, неправильную программу, включая }{
:
ls |perl -lne 'print $_; }{ print "$. Files"'
который внутренне преобразуется в этот код:
LINE: while (defined($_ = <ARGV>)) {
print $_; }{ print "$. Files";
}
Ответ 17
Легко начать с Оператор космического корабля.
$a = 5 <=> 7; # $a is set to -1
$a = 7 <=> 5; # $a is set to 1
$a = 6 <=> 6; # $a is set to 0
Ответ 18
Это мета-ответ, но Perl Tips архивы содержат всевозможные интересные трюки, которые можно сделать с помощью Perl. Архив предыдущих советов доступен в режиме онлайн для просмотра и может быть подписан через список рассылки или подачу атома.
Некоторые из моих любимых советов включают создание исполняемых файлов с PAR, используя autodie для автоматического исключения исключений и использования switch и smart-match в Perl 5.10.
Раскрытие информации: Я являюсь одним из авторов и сторонников Perl-советов, поэтому я, очевидно, очень высоко ценю их.;)
Ответ 19
map - не только потому, что он делает один код более выразительным, а потому, что он дал мне импульс прочитать немного больше об этом "функциональном программировании".
Ответ 20
Мое голосование пойдет для групп (? {}) и (?? {}) в регулярных выражениях Perl. Первый выполняет код Perl, игнорируя возвращаемое значение, второй выполняет код, используя возвращаемое значение как регулярное выражение.
Ответ 21
Предложение 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";
}
Ответ 22
Оператор m//
имеет некоторые неясные частные случаи:
- Если вы используете
?
в качестве разделителя, он соответствует только одному, если вы не вызываете reset
.
- Если вы используете
'
в качестве разделителя, шаблон не интерполируется.
- Если шаблон пуст, он использует шаблон из последнего успешного совпадения.
Ответ 23
while(/\G(\b\w*\b)/g) {
print "$1\n";
}
the\G anchor. Он горячий.
Ответ 24
Нулевой дескриптор файла алмазный оператор <>
имеет свое место в создании инструментов командной строки. Он действует как <FH>
для чтения из дескриптора, за исключением того, что он волшебным образом выбирает то, что было найдено первым: имена файлов командной строки или STDIN. Взято из perlop:
while (<>) {
... # code for each line
}
Ответ 25
Специальные кодовые блоки, такие как BEGIN
, CHECK
и END
. Они происходят из Awk, но работают по-разному в Perl, потому что они не основаны на записи.
Блок BEGIN
может использоваться для указания некоторого кода для фазы синтаксического анализа; он также выполняется, когда вы выполняете проверку синтаксиса и переменной perl -c
. Например, чтобы загрузить переменные конфигурации:
BEGIN {
eval {
require 'config.local.pl';
};
if ([email protected]) {
require 'config.default.pl';
}
}
Ответ 26
rename("$_.part", $_) for "data.txt";
переименовывает data.txt.part в data.txt, не повторяя себя.
Ответ 27
Немного неясным является "оператор" тильд-тильды, который заставляет скалярный контекст.
print ~~ localtime;
совпадает с
print scalar localtime;
и отличается от
print localtime;
Ответ 28
tie, интерфейс привязки переменных.
Ответ 29
"Режим отчаяния" конструкций управления контуром Perl, который заставляет их искать стек, чтобы найти подходящую метку, позволяет некоторым любопытным поведениям, которые Test:: More использует, к лучшему или худшему.
SKIP: {
skip() if $something;
print "Never printed";
}
sub skip {
no warnings "exiting";
last SKIP;
}
Там маленький известный файл .pmc. "use Foo" будет искать Foo.pmc в @INC до Foo.pm. Это предназначалось для того, чтобы сначала загружать скомпилированный байт-код, но Module:: Compile использует это для кэширования исходных фильтрованных модулей для более быстрого времени загрузки и более легкая отладка.
Возможность включения предупреждений в ошибки.
local $SIG{__WARN__} = sub { die @_ };
$num = "two";
$sum = 1 + $num;
print "Never reached";
Это то, что я могу думать о моей голове, о которой не упоминалось.
Ответ 30
Оператор goatse *
:
$_ = "foo bar";
my $count =()= /[aeiou]/g; #3
или
sub foo {
return @_;
}
$count =()= foo(qw/a b c d/); #4
Это работает, потому что назначение списка в скалярном контексте дает количество элементов в списке, который назначается.
*
Обратите внимание, что это не оператор