Скрытые черты 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

Ответ 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/&‎nbsp;/ /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";
}

Ответ 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

Это работает, потому что назначение списка в скалярном контексте дает количество элементов в списке, который назначается.

* Обратите внимание, что это не оператор