Чтобы писать на Perl, надо быть красноглазым линуксоидом, безумным гением или самоубийцей. Хотя нет, для самоубийц есть более интересные языки.
Предыдущая часть:
Какие первые ассоциации вызывает Perl? Он был создан красноглазым линуксоидом юниксоидом Ларри Уоллом в 1987 году для обработки текстовых отчётов. Поэтому его главная фишка это регулярные выражения.
Их мы конечно обсудим, но у Перла есть ещё много особенностей. Я застал уже последнюю версию Perl 5. Поэтому буду писать, опираясь на неё.
На всякий случай: все мои подколки исключительно шутливые.
Синтаксис
Можно сказать, что синтаксис С-подобный. Посмотрим такой пример:
С виду всё узнаваемо. Есть подпрограмма, обозначенная как sub, есть стандартный for-цикл, только к именам переменных зачем-то приписан знак доллара. Ну а кроме этого, вроде всё норм?
Узнаем дальше, а пока плеснём немного бензина в костёр.
Это три условия, и все они выполняются, то есть печатают "5". Первое это привычный if, который не вызывает вопросов. Второе это
unless, или if наоборот. По-русски можно сказать "окромя". Типа, окромя когда $count не равен 5, напечатай. Наконец, третья конструкция такая же, но условие написано уже после оператора print. Суть та же самая, просто порядок слов другой.
Зачем он это придумал? Because fuck you потому что мог. Ведь чем больше у программиста свободы самовыражения, тем лучше. Поехали дальше.
Здесь могло быть стандартное else if, но нет. Именно elsif, и это самое чудовищное и бессмысленное издевательство над логикой и структурой языка, и человеческого, и программного (аналогичная гадость есть у Питона в виде elif 🤮🤮🤮 и у PHP в виде elseif, но у PHP оно не обязательное).
Подпрограммы и область видимости переменных
Повторю первый пример:
Можно заметить, что функция test() использует переменную $count, которая объявлена снаружи. Иначе говоря, переменная $count является глобальной. Есть способ сделать её локальной:
my $count = 3;
И вот уже функция её не видит. Слово my значит "моё", всё логично. Также в цикле, который внутри функции, используется переменная $i. Она будет видна внутри функции после окончания цикла. Но если написать цикл с my $i, то после цикла её не станет. Здесь у нас паритет с другими языками, где переменные могут быть локальными внутри блока.
А как же нам передать в подпрограмму какой-нибудь параметр? Допустим, мы пишем вызов с параметрами 5 и 10:
test(5, 10)
А объявление подпрограммы по идее должно выглядеть так:
sub test($x, $y)
Но не тут-то было. Параметров у подпрограммы нет вообще. Она должна добыть их в бою:
Получается следующее. При вызове функции в какой-то стэкообразный буфер кладутся параметры 5 и 10. Сама же функция считывает их из буфера с помощью команды shift и называет так, как хочет. Выходит, что сигнатура функции никак не определена. Мы можем передавать в неё сколько угодно параметров, а она может считывать столько параметров, сколько хочет.
Попробуем считать больше параметров, чем было передано:
Никаких проблем, просто $z и $w окажутся пустыми:
x = 5, y = 10, z = , w =
Есть и другой способ:
Надо быть очень уравновешенным человеком, чтобы на этом месте не бросить стулом в монитор. Что это за закорюки, @_?
Как бы сказать... Давайте посмотрим ещё один вариант:
Да какого чёрта здесь вообще происходит?! Почему пишется то @params, то $params?
Типы переменных
Как вы уже догадались, Perl это не типизированный язык. Но есть одно отличие, которое относится к способу обращения к переменной, и оно всё время было у нас перед глазами. Это тот самый знак доллара. Он означает скалярное, то есть простое, или примитивное значение переменной:
$x = 5
Далее, знак @ означает массив:
@x = (1, 2, 3);
print $x[1];
И обратите внимание, что переменная x одна и та же, но когда мы инициализируем массив, то пишем @x, а когда обращаемся к элементу массива, пишем $x. То есть знаки $ и @ это не части имени переменной, а модификаторы доступа. В одном случае имеем дело с целым массивом, в другом с элементом массива скалярного типа.
Можно теперь выдохнуть и ещё раз посмотреть, что происходит, когда мы получаем параметры функции:
my ($x, $y, $z) = @_;
Символ подчёркивания _ это магическая встроенная переменная, которая в контексте обозначает тот самый буфер с переданными в функцию параметрами. Мы хотим получить доступ ко всему буферу, как к массиву, поэтому пишем @_. Далее весь этот буфер мы отображаем на список из нескольких скалярных переменных (аналогичные техники есть в других языках, и возможно пришли именно отсюда).
Либо можем просто скопировать этот буфер в другой массив и далее работать с параметрами как с массивом:
@params = @_;
print $params[0];
Третий тип доступа это хэш-объекты (ключ-значение) с модификатором %:
%color = ( r => 0, g => 255, b => 0 );
print $color{g};
На этом придётся закруглиться, хотя остались ещё указатели, итераторы, операции работы с файлами, которые выглядят СОВСЕМ не так, как обычные. Полно разной дичи, которую, будет на то интерес, разберём ещё отдельно.
Регулярные выражения
Следует заметить, что на данный момент поддержка регулярных выражений есть в каждом уважающем себя языке, и поэтому использовать для них Perl уже необязательно.
Регулярное выражение (regexp) это специальным образом составленный шаблон, с помощью которого можно искать или заменять определённые куски текста.
Не вдаваясь в подробности (кто знает – тот знает, а кто не знает, лучше погуглить), шаблон может обозначать что-то вроде "текст должен начинаться с большой буквы", "текст должен содержать только буквы A..Z и цифры 0..9", "текст должен иметь ровно три пробела" и т.д. Известный пример это шаблон для проверки корректности адресов электронной почты (один из его не самых сложных вариантов присутствует в мемасике в начале статьи). Сложность шаблона практически ничем не ограничена, можно создавать самые навороченные условия.
Если в других языках регулярные выражения присутствуют в виде функций типа preg_match(), то в Перле они встроены прямо в синтаксис языка.
Например, мы прочитали из файла строку $line, и хотим избавиться от символов переноса строки в конце:
$line =~ s/[\n\r]+$//;
Дословно этот шаблон означает: найти любое количество символов \n или \r, расположенных перед концом строки, и удалить их. Самое пугающее тут для меня то, что выражение, будучи по сути строкой, пишется без всяких ограничителей, то есть в синтаксис языка внезапно внедряется совершенно чуждый синтаксис выражения.
В PHP это можно было бы написать так:
$line = preg_replace('/[\n\r]+$/', '', $line);
Здесь уже нормальный вызов функции с нормальными строковыми параметрами, поэтому он не вызывает тревоги и растерянности.
Заключение
Perl это довольно своеобразный язык, который сходу трудно понять, но надо отдать должное, что если им овладеть, то можно довольно эффективно писать программы, особенно программы-обработчики различных данных.
Современная версия поддерживает и ООП, и модульность, и одно из преимуществ Перла это огромное количество библиотек на все случаи жизни.
Читайте дальше: