Недавно я приобрел копию книги «Программирование Perl», которую в сообществе Perl часто называют «Верблюжьей книгой». Прочитав первые 4 главы, я решил поделиться несколькими интересными для меня моментами, связанными с Perl.
While <> is True
Допустим, у нас есть следующий файл с именем logos.txt
.
Onion
Camel
Raptor
И в той же директории у нас есть следующая программа scratch.pl
.
open my $fh, '<', 'logos.txt' or die;
while (my $logo = <$fh>) {
print $logo;
}
close $fh;
Как и ожидалось, наша программа печатает содержимое файла logos.txt
.
$ perl ./scratch.pl
Onion
Camel
Raptor
Однако я никогда не задумывался над тем, почему цикл не завершается, когда <>
считывает пустую строку в logos.txt
? Разве <>
не должен возвращать пустую строку, которая является ложным значением?
Согласно Programming Perl, причина, по которой цикл не завершается, заключается в том, что <>
считывает новую строку в конце строки, поэтому мы получаем "n"
, что является истинным значением. Оказывается, это обман, и на самом деле причина в том, что while (my $logo = <$fh>) ...
расширяется в while (defined (my $logo = <$fh>)) ...
, а "n"
— это определенное значение.
Мы можем показать это, департировав код с помощью B::Deparse.
$ perl -MO=Deparse,-p,-sCi2 -ne 42
LINE: while (defined(($_ = readline(ARGV)))) {
'???';
}
-e syntax OK
Heredocs может выполнять команды оболочки
Большинство программистов на Perl знают, что если заключить завершающую строку heredocs в одинарную кавычку, то это предотвратит интерполяцию переменных.
my $var = 12;
print <<'EOS';
Hello
$var = 12
EOS
В выводе программы видно, что $var
не была интерполирована.
$ perl ./scratch.pl
Hello
$var = 12
Но знаете ли вы, что если заключить завершающую строку в обратную кавычку, то каждая строка будет выполняться как команда оболочки?
print <<`EOC`;
echo this is a shell command
echo this is also a shell command
EOC
Запустив эту программу, мы видим, что команды echo были выполнены.
$ perl ./scratch.pl
this is a shell command
this is also a shell command
Оператор запятая
Я всегда воспринимал запятые как нечто само собой разумеющееся, не подозревая, что на самом деле они являются оператором.
Вы когда-нибудь задумывались, почему списки возвращают свой последний элемент при скалярной оценке? Оказывается, это связано с оператором запятой.
В скалярном контексте оператор запятой «,» игнорирует свой первый аргумент и возвращает второй элемент, оцененный в скалярном контексте.
Это означает, что в скалярном контексте список (11, 22, 33)
будет иметь значение 33. Первый оператор запятой отбросит 11, а затем вернет (22, 33)
, оцененный в скалярном контексте, который будет оценен, отбросив 22 и вернув 33.
Автоинкрементные строки
В perl можно автоматически увеличивать не только числа, но и строки. Чтобы увеличить строку, она должна соответствовать regex /^[a-zA-Z]*[0-9]*z/
.
Строки из символов одного алфавита увеличиваются интуитивно.
$ perl -E 'my $v = "a"; say ++$v'
b
$ perl -E 'my $v = "B"; say ++$v'
C
Что произойдет, если мы увеличим не алфавитно-цифровой символ. Выдаст ли он следующий символ ASCII? Оказывается, при инкрементировании неалфавитно-цифровые символы рассматриваются как 0. К счастью, если мы используем предупреждения, Perl предупредит нас об этом.
$ perl -W -E 'my $v = "-"; say ++$v'
Argument "-" treated as 0 in increment (++) at -e line 1.
1
Что произойдет, если мы увеличим z
, который находится в конце алфавита? Вернемся ли мы обратно к a
? Вот здесь все становится интересным. Perl увеличивает строку так же, как и в обычной системе счисления. Так же, как 9 + 1 = 10
в десятичной z + 1 = aa
в … строчной.
$ perl -E 'my $v = "z"; say ++$v'
aa
Вот еще несколько примеров, демонстрирующих магию автоинкрементирования строк.
$ perl -W -E 'my $v1 = "foo"; say ++$v1'
fop
$ perl -W -E 'my $v1 = "az"; say ++$v1'
ba
$ perl -W -E 'my $v1 = "a9"; say ++$v1'
b0