Аргументы
Аргументы
Несомненно, подпрограммы, выполняющие одно определенное действие, полезны, однако перед вами откроются совершенно новые горизонты, когда вы сможете передавать в подпрограмму аргументы.
В Perl после вызова подпрограммы следует список, заключенный в круглые скобки, которые обеспечивают автоматическое присваивание элементов данного списка на период выполнения этой подпрограммы специальной переменной с именем @_. Подпрограмма может обратиться к этой переменной и получить число аргументов и их значения. Например:
sub say_hello_to (
print "hello, $_[0]!\n" # первый параметр }
Здесь мы видим ссылку на $_[0] — первый элемент массива @_. Обратите внимание: несмотря на внешнее сходство, значение $_ [ 0 ] (первый элемент массива @_) не имеет ничего общего с переменной $_ (самостоятельной скалярной переменной). Не путайте их! Из этого кода видно, что подпрограмма приветствует того, чье имя мы указываем в качестве первого параметра. Это значит, что ее можно вызвать так:
say_hello_to("world"); # выдает hello, world $х = "somebody";
say_hello_to($x); # выдает hello, somebody say_hello_to("me")+say_hello_to("you"); # а теперь приветствует себя и вас
В последней строке возвращаемые значения явно использованы не были, однако для определения суммы Perl сначала должен вычислить все ее слагаемые, поэтому подпрограмма была вызвана дважды.
Вот пример с использованием более одного параметра:
sub say (
print "$_[0], $_[!]!\n";
}
say("hello","world"); # опять hello world
say ("goodbye", "cruel world"); # goodbye cruel world - популярная фраза из фильмов
Избыточные параметры игнорируются, т.е. если вы никогда не заглядываете в $_ [ 3 ], языку Perl это абсолютно все равно. Недостающие параметры также игнорируются, и если вы попытаетесь обратиться за пределы массива @_, как и любого другого массива, то просто получите в ответ undef.
Переменная @_ является локальной для подпрограммы. Если для @_ установлено глобальное значение, то оно перед вызовом подпрограммы сохраняется, а после возврата из подпрограммы восстанавливается. Это также означает, что подпрограмма может передавать аргументы в другую подпрограмму, не боясь "потерять" собственную переменную @_; вложенный вызов подпрограммы точно так же получает собственную переменную @_.
Давайте вернемся к программе сложения а и b из предыдущего раздела. Вот подпрограмма, которая складывает любые два значения, а именно два значения, передаваемые в нее как параметры:
sub add_two {
return $_[0] + $_[!];
1
print add_two(3,4); # выводит значение 7
$с = add_two(5,6); # $с получает значение 11
Давайте обобщим эту подпрограмму. Что, если нам нужно сложить 3, 4 или 100 значений? Это можно было бы сделать с помощью цикла, например:
sub add (
$sum = 0; # инициализировать сумму
foreach $_ (@_) {
$sum += $_; # прибавить все элементы
}
return $sum # последнее вычисленное выражение: сумма всех элементов }
$а = add(4,5,6); # складывает 4+5+6=15 и присваивает переменной $а print add(1,2,3,4,5); # выводит 15 print add (1..5); # тоже выводит 15, потому что список 1..5 раскрывается
Что, если бы переменная с именем $sum использовалась у нас раньше? При вызове подпрограммы add мы просто потеряли бы ее значение. В следующем разделе мы увидим, как избежать этого.
Базовые средства вводавывода
Базовые средства ввода-вывода
Базы данных произвольного доступа
Например, у нас может быть ряд записей со следующими данными:
40 символов — имя, один символ — инициал, 40 символов — фамилия и двухбайтовое целое — возраст. Таким образом, длина каждой записи состав-ляет 83 байта. Если бы мы читали все зти данные в базе данных, то делали бы зто порциями по 83 байта до тех пор, пока не добрались до конца. Если бы мы хотели перейти к пятой записи, то мы пропустили бы четыре раза по 83 байта (332 байта) и прочитали бы непосредственно пятую запись.
Perl поддерживает программы, которые используют файл с подобными записями. Помимо того, что вы уже знаєте, понадобятся еще несколько операций:
1. Открытие файла на диске для чтения и записи.
2. Переход в зтом файле на произвольную позицию.
3. Выборка данных фиксированной длины, а не до следующего символа новой строки.
4. Запись данных блоками фиксированной длины.
В функции open перед спецификацией, задающей способ открытия файла (для чтения или записи), необходимо записать знак плюс, указав таким образом, что данный файл в действительности открывается и для чтения, и для записи. Например:
open (А, "+<Ь"); # открьеть файл b для чтения-записи (ошибка, если файл отсутствует)
open(C, "+>d"); # создать файл d с доступом для чтения-записи
open(Е, "+”f"); # открить или создать файл f с доступом для чтения-записи
Отметим, что все, что мы сделали — зто добавили знак плюс к специфи-кации, задающей направление ввода-вывода данных в файл.
Открыв файл, мн должны перейти на определенную позицию в нем. Зто делается с помощью функции seek, которая принимает те же три параметра, что и библиотечная програм ма./yeeA^.?/ Первый параметр — зто дескриптор файла, а второй параметр задает смещение, которое интерпретируется в совокупности с третьим параметром. Как правило, в качестве третього параметра ставится нуль, чтобы второй параметр задавал абсолютную позицию для следующего чтения из файла или записи в файл. Например, чтобы перейти к пятой записи в дескрипторе файла names (как описано выше), можно сделать так:
seek(NAMES,4*83,0) ;
После перемещения указателя в файле на нужную позицию следующая операция ввода или вывода будет начинаться с зтой позиции. Для вывода используйте функцию print, но не забудьте, что записываемые данные должны иметь строго определенную длину. Чтобы сформировать запись правильной длины, можно воспользоваться функцией pack::
print NAMES pack("A40 A A40 s", $first, $middle, $last, $age);
В данном случае pack задает 40 символов для $ first, один символ — для $middle, еще 40 символов — для $last и короткеє целое (два байта) для $аде. Определенная таким образом запись будет иметь в длину 83 байта и начинаться с текущей позиции в файле.
Наконец, нам нужно узнать, как выбрать конкретную запись. Конструк-ция <names> возвращает все данные, начиная с текущей позиции і до следующего символа новой строки, однако в нашем случае предполагасгея, что данные занимают 83 байта й, вероятно, символ новой строки непосред-ственно в записи отсутствует. Позтому вместо нее мы используем функцию read, которая по внешнему виду и принципу работы очень похожа на свою UNIX-коллегу:
$count = read(NAMES, $buf, 83);
Первый параметр функции read — дескриптор файла. Второй параметр — зто скалярная переменная, в которую будут записаны прочитанные данные. Третий параметр задает количество байтов, которые нужно прочитать. Возвращает функция read количество фактически прочитанных байтов; как правило, оно равно затребованному количеству байтов, если только дескриптор файла открыт и если вы не находитесь слишком близко к концу файла.
Получив зти 83-символьные данные, разбейте их на компоненты с помощью функции unpack:
($first, $middle, $last, $age) = unpack("A40 A A40 s", $buf);
Как видно, строки, определяющие формат, в функциях pack и unpack — одинаковы. В большинстве программ зту строку заносят в переменную, указы-ваемую в начале программы, и даже вычисляют с помощью функции pack длину записей, а не используют везде константу 83:
$names = "А40 А А40 s";
$names_length = length(pack($names)); # вероятно, 83
Базы данных с записями переменной длины (текстовые)
Базы данных с записями переменной длины (текстовые)
Многие системные базы данных ОС UNIX (й довольно большое число пользовательских баз данных) представляют собой набори понятных чело-веку текстовых строк, каждая из которых образует одну запись. Например, каждая строка файла паролей соответствует одному пользователю системы, а строка файла хостов — одному хост-имени.
Корректируются зти базы данных в основном с помощью простих текстовых редакторов. Процедура обновлення базы данных состоит из чтения ее в какую-то временную область (память или другой дисковий файл), внесення необходимых изменений и либо записи результата обратно в исходный файл, либо создания нового файла с тем же именем, с одновре-менным удалением или переименованием старой версии. Зтот процесе можно рассматривать как разновидность копирования: данные копируются из исходной базы данных в новую ее версию с внесением изменений в процессе копирования.
Perl поддерживает редактирование такого типа в строчно-ориентирован-ных базах данных методом редактирования на месте. Редактирование на месте — зто модификация способа, посредством которого операция "ромб" (<>) считывает данные из списка файлов, указанного в командной строке. Чаще всего зтот режим редактирования включается путем установки аргу-мента командной строки -і, но его можно запустить и прямо из программы, как показано в приведенных ниже примерах.
Чтобы запустить режим редактирования на месте, присвойте значение скалярной переменной $ л і. Оно играет важную роль и будет сейчас рассмот-рено.
Когда используется конструкция о и переменная $ЛI имеет значение, отличное от undef, к списку неявних действий, которые выполняет операция "ромб", добавляются шаги, отмеченные в приведенном ниже коде комментарием ## inplace ##:
$ARGV = shift 6ARGV;
open(ARGV,"<$ARGV") ;
rename($ARGV,"$ARGV$AI"); ## INPLACE ## unlink($ARGV); ## INPLACE ##
open(ARGVOUT,">$ARGV"); ## INPLACE ## select(ARGVOUT) ,- ## INPLACE ##
В результате в операции "ромб" при чтении используется старый файл, а запись в дескриптор файла по умолчанию осуществляется в новую копию зтого файла. Старый файл остается в резервной копии, суффикс имени файла которой равен значеним переменной $AI. (При зтом биты прав доступа копируются из старого файла в новый.) Зти шаги повторяются каждый раз, когда новый файл берется из массива @argv.
Типичные значення переменной $ЛI — .bak или ~, т.е. резервные файлы создаются почти так же, как зто делается в текстовом редакторе. Странное и полезное значение $ЛI — пустая строка (""), благодаря которой старый файл после редактирования аккуратно удаляется. К сожалению, если система при выполнении вашей программы откажет, то вы потеряете все свои старые данные, позтому значение "" рекомендуется использовать только храбрецам, дуракам и излишне доверчивым.
Вот как можно путем редактирования файла паролей заменить регистра-ционный shell всех пользователей на /bin/sh'.
8ARGV = ("/etc/passwd"); # снабдить информацией операцию "ромб"
$"1
== ".bak"; # для надежности записать /etc/passwd.bakwhile (о) { # основной цикл, по разу для каждой строки файла
# /etc/passwd s#: (л: ] *$#:/bin/sh#; # заменить shell на /bin/sh print; # послать выходную информацию в ARGVOUT: новий
# /etc/passwd
Как видите, зта программа довольно проста. Однако ее можно заменить всего лишь одной командой с несколькими аргументами командной строки, например:
perl -р -і.bak -е 's#: [л:]*$#:/bin/sh#' /etc/passwd
Ключ -р охватывает вашу программу циклом while, который включает оператор print. Ключ -і устанавливает значение переменной $^1. Ключ -е определяет следующий аргумент как фрагмент Perl-кода для тела цикла, а последний аргумент задает начальнеє значение массива @argv.
Более подробно аргументы командной строки рассматриваются в книге Programming Perl и на man-странице perlrun.
Библиотеки и модули
Библиотеки и модули
Для простых программ вы уже теперь можете свободно писать собственные Perl-подпрограммы. Когда же задачи, для решения которых вы применяете Perl, станут более сложными, вам иногда будет приходить в голову мысль: "Кто-то, должно быть, это уже делал". И в подавляющем большинстве случаев вы окажетесь правы.
Действительно, другие люди уже написали коды для решения большинства распространенных задач. Более того, они поместили их либо в стандартный дистрибутив Perl, либо в бесплатно загружаемый архив CPAN. Чтобы использовать этот код (и сэкономить немного времени), вам придется разобраться в том, как пользоваться Perl-библиотекой. Этот вопрос вкратце освещался в главе 19.
Одно из преимуществ использования модулей из стандартного дистрибутива состоит в том, что потом вы можете предоставлять свою программу другим пользователям, при этом не придется предпринимать никаких специальных мер. Это объясняется тем, что одна и та же стандартная библиотека доступна Perl-программам практически везде.
Если вы решите обратиться к стандартной библиотеке, то в конечном итоге сэкономите свое время. Нет никакого смысла вновь изобретать велосипед. Следует понимать, однако, что эта библиотека содержит очень много материала. Одни модули могут быть исключительно полезны, тогда как другие совершенно не подходят для решения ваших задач. Например, некоторые модули полезны лишь в том случае, если вы создаете дополнения к языку Perl.
Чтобы прочитать документацию, относящуюся к стандартному модулю, воспользуйтесь программой man или perldoc (если они у вас есть) либо своим Web-броузером, если речь идет о HTML-версиях этой документации. Если ничего не получается, поищите в файлах самого модуля: документация включена в состав каждого модуля (в pod-формате). Чтобы найти модуль у себя в системе, попробуйте выполнить из командной строки следующую Perl-программу:
# для (большинства) Unix-подобных shell peri -e 'print "@INC\n"'
# для (некоторых) других интерпретаторов команд
peri -e "print join(' ',"@INC),\n"
Вы должны найти модуль в одном из каталогов, перечисленных этой командой.
BITFTP
BITFTP — это почтовый сервер для пользователей сети BITNET. Вы посылаете на него сообщения электронной почты с запросами на получение файлов, а сервер посылает по электронной почте указанные вами файлы. Сейчас BITFTP обслуживает только тех пользователей, которые посылают на него почту с узлов, непосредственно включенных в BITNET, EARN или NetNorth. BITFTP — это общедоступный сервис Принстонского университета. Чтобы воспользоваться услугами BITFTP, пошлите почтовое сообщение с необходимыми FTP-командами по адресу BITFTP@PUCC. Если вы хотите получить полный справочный файл, пошлите в теле сообщения слово HELP. Ниже приведено тело сообщения, которое следует послать на BITFTP:
FTP ftp.ora .corn NETDATA USER anonymous PASS ваш электронно-почтовый Internet-адрес (а не BITNET-адрес) CD /published/oreilly/nutshell/perl/learning_perl2 DIR GET README GET examples.tar.gz QUITВопросы, касающиеся самого BITFTP, следует направлять на узел BIT-NET MAINT@PUCC.
Благодарности первое издание
Во-первых, я от всего сердца благодарю Чика Уэбба и фирму Taos Mountain Software (Кремниевая долина). Ребята из TMS предоставили мне возможность написать для них (при значительном содействии Чика) ввод-ный курс по языку Perl и прочитать этот курс несколько раз. Этот опыт дал мне мотивы и ресурсы для написания и многократного прочтения нового, моего собственного курса, на базе которого и построена эта книга. Не думаю, что без содействия сотрудников TMS я занимался бы этим, и желаю им всем больших успехов в маркетинге их курса. (А если они ищут хороший текст для переработки своего курса, то у меня как раз есть одно предложение...)
Спасибо моим рецензентам: "крестному отцу" языка Perl Ларри Уоллу (естественно), Ларри Кистлеру (руководителю службы подготовки кадров фирмы Pyramid), моему коллеге по преподаванию Per] Тому Кристиансену и слушателям курсов по Perl из фирм Intel и Pyramid, а также сотрудникам издательства O'Reilly & Associates Тане Херлик, Лару Кауфману, Пенни Мюльнеру, Линде Мюи и Энди Ораму.
Эта книга была полностью написана и отредактирована на моем персо-нальном компьютере Apple Macintosh Powerbook (сначала модели 140, теперь 160). В процессе работы я чаще всего находился вне своего кабинета — иногда в парке, иногда в гостинице, иногда в горах, ожидая хорошей погоды для лыжных прогулок, но чаще всего в ресторанах. По сути дела, значительную часть книги я написал в пивном баре Beaverton McMenamin's недалеко от дома. В пабах сети McM's варят и подают самое вкусное пиво, самый лучший творожный пудинг и самые жирные сэндвичи в округе. В этой идеальной для работы обстановке я выпил множество пинт пива и съел гору пудинга, а мой Powerbook поглотил массу киловатт-часов электроэнергии, устраиваясь на тех четырех столах, где есть розетки. Благодарю замечательный персонал бара McM's за эту электроэнергию, а также за гостеприимство, радушие и любезность (и бесплатное место для работы). Кроме того, благодарю ресто-ран Beaverton Chili's, где я начал работать над этой книгой. (Но у них возле стойки не оказалось розеток, поэтому когда я нашел McM's, то перешел туда, чтобы сберечь аккумуляторы.)
Спасибо всем пользователям Internet (особенно подписчикам телеконфе-ренции сотр.lang.perl) за их постоянную поддержку, оказываемую Ларри и мне, и за бесконечные вопросы на тему о том, как заставить Perl работать. Благодарю также Тима 0'Рейли — за даосизм.
Наконец, особая, огромная персональная благодарность — моему другу Стиву Тэлботту, который направлял меня на каждом этапе этого пути (в частности, он предложил сделать "прогулку" по стране Perl, впечатления от которой представлены в конце первой главы). Его редакторская критика всегда была справедливой, а его удивительная способность бить меня по голове с исключительной нежностью позволила мне сделать мою книгу произведением искусства, которым я крайне доволен.
Как всегда, выражаю особую благодарность Лайлу и Джеку за то, что они нашили меня почти всему тому, что я знаю о писательском ремесле.
И, наконец, безмерная благодарность — моему другу и партнеру Ларри Уоллу за то, что он дал всем нам Perl.
Одна "Л" — Рэндал — книгу написала, Вторая — лама — на обложку прискакала. Но кто все это изобрел? То целых три "Л" — Ларри Уолл!
Благодарности второе издание
Я хотел бы поблагодарить Ларри Уолла за создание Perl, членов группы Perl Porters за их постоянные усилия по сопровождению языка и все Perl-сообщество за готовность помогать друг другу.
Спасибо также Джону Оруонту, Нэйту Торкингтону и Ларри Уоллу за рецензирование главы, посвященной CGI.
Блоки операторов
Блоки операторов
Блок операторов — это последовательность операторов, заключенная в парные фигурные скобки. Блок операторов выглядит следующим образом:
(
первыи_оператор;
второй_оператор;
третий_оператор;
последний_оператор;
>
Perl выполняет операторы по очереди, начиная с первого и кончая последним. (Позднее вы узнаете о том, как можно изменять порядок выполнения в блоке, но пока достаточно и этого.)
Синтаксически блок операторов принимается вместо любого одиночного оператора, но обратное не верно.
Завершающая точка с запятой, стоящая за последним оператором, не обязательна. Таким образом, вы можете разговаривать на языке Perl с С-акцентом (точка с запятой присутствует) или с паскалевским акцентом (точка с запятой отсутствует). Чтобы облегчить последующее добавление операторов, мы обычно рекомендуем опускать точку с запятой лишь в том случае, если блок занимает целую строку. Сравните примеры этих стилей в следующих двух блоках if:
if ($ready) ( $hungry++ } if ($tired) (
$sleepy = ($hungry + 1) * 2;
}
Чтение дескриптора каталога Открыв
opendir(ETC,"/etc") II die "no etc?: $!";
while ($name = readdir(ETC)) f t скалярный контекст, по одному на цикл
print "$name\n"; #выводит ., .., passwd, group и т.д. 1 closedir(ETC) ;
А вот как можно получить все имена в алфавитном порядке с помощью функции sort:
opendir(ETC,"/etc") || die "no etc?: $!";
foreach $name (sort readdir(ETC)) ( # списочный контекст с сортировкой
print "$name\n"; #выводит ., .., passwd, group и т.д. ) closedir(ETC) ;
В этот список включены имена файлов, которые начинаются с точки. Это не похоже на результат развертывания, выполненного с использованием <*>, при котором имена, начинающиеся с точки, не возвращаются. С другой стороны, это похоже на результат работы команды echo* shell.
* Точнее говоря — это порядок, в котором имена файлов расположены в каталоге, т.е. тот же "беспорядочный порядок", в котором вы получаете файлы в ОС UNIX в результате вызова команды .find или Is -f.
** Это означает, что при работе с опцией-w вам придется использовать цикл while (defined
($name = readdir (...)).
Что еще почитать о сетях
Что еще почитать о сетях
О сетях можно говорить и говорить, но мы дадим ссылки на источники, которые помогут вам перейти от разговоров к делу. В главе 6 книги Programming Perl и на man-странице perlipc(l) описано межпроцессное взаимодействие в общем; на man-странице IO::Socket(3) — объектная библиотека; на man-странице Socket(3) — низкоуровневый интерфейс к гнездам. Более опытным программистам рекомендуем книгу Unix Network Programming (by Richard Stevens, Addison-Wesley), в которой очень хорошо освещены все вопросы данной темы. Будьте, однако, осторожны: большинство книг по программированию гнезд написаны С-программистами.
Что такое дескриптор файла
Что такое дескриптор файла
Дескриптор файла в Perl-программе — это имя соединения для ввода-вывода между вашим Perl-процессом и внешним миром. Мы уже видели дескрипторы файлов и пользовались ими, сами того не зная: stdin — это дескриптор, которым именуется соединение между Perl-процессом и стандартным вводом UNIX. Аналогичным образом в Perl существует stdout (для стандартного вывода) и stderr (для стандартного вывода ошибок). Это те же самые имена, что и используемые библиотекой стандартного ввода-вывода в С и C++, которую Perl задействует в большинстве операций ввода-вывода.
Имена дескрипторов файлов похожи на имена помеченных блоков, но они берутся из другого пространства имен (поэтому у вас может быть скаляр $fred, массив Sfred, хеш %fred, подпрограмма sfred, метка fred, а теперь и дескриптор файла fred). Как и метки блоков, дескрипторы файлов используются без специального префиксного символа, поэтому их можно спутать с существующими или возможными в будущем зарезервированными словами (для команд, подпрограмм и др.). Рекомендуем составлять дескрипторы файлов только из прописных букв. Во-первых, они будут хорошо выделяться в тексте программы, и, во-вторых, благодаря этому программа не даст сбой при введении нового зарезервированного слова.
Что такое формат Помимо всего
В Perl существует понятие шаблона для написания отчета, который называется форматом. В формате определяется постоянная часть (заголовки столбцов, метки, неизменяемый текст и т.д.) и переменная часть (текущие данные, которые вы указываете в отчете). Структура формата близка собственно к структуре вывода и подобна форматированному выводу в Коболе или выводу при помощи клаузы print using в некоторых реализациях Бейсика.
Использование формата предполагает выполнение трех операций:
1. Определение формата.
2. Загрузка данных, подлежащих печати, в переменные части формата (поля).
3. Вызов формата.
Чаще всего первый этап выполняется один раз (в тексте программы, чтобы формат определялся во время компиляции)*, а два остальных этапа — многократно.
* Форматы можно создавать и во время выполнения, пользуясь функцией eval (см. книгу Programming Perl) и man-страницу perlform(l).
Что такое хеш Хеш* похож на массив
Элементы хеша не стоят в каком-то конкретном порядке. Можете рассматривать их как стопку библиографических карточек. Верхняя половина каждой карточки — это ключ, а нижняя — значение. Каждый раз, когда вы помещаете в хеш значение, создается новая карточка. Когда нужно изменить значение, вы указываете ключ, и Perl находит необходимую карточку. Поэтому порядок карточек, по сути дела, роли не играет. Perl хранит все карточки (т.е. пары ключ-значение) в особом внутреннем порядке, который облегчает поиск конкретной карточки, поэтому при поиске не приходится просматривать все пары. Порядок хранения карточек изменять нельзя, так что даже и не пытайтесь**.
CPAN не только стандартная библиотека
CPAN: не только стандартная библиотека
Если вы не можете найти в стандартной библиотеке модуль, соответствующий вашим потребностям, все равно существует вероятность, что кто-то уже написал код, который будет вам полезен. Есть много превосходных библиотечных модулей, которые не включены в стандартный дистрибутив — по различным причинам практического, политического и вздорного характера. Чтобы выяснить, что есть в наличии, можно заглянуть в Comprehensive Perl Archive Network (CPAN). 0 CPAN мы говорили в предисловии.
Вот основные категории модулей, которые можно получить из CPAN:
• Модуль формата листинга.
• Базовые модули Perl, расширения языка и средства документирования.
• Модули, обеспечивающие поддержку разработки.
• Интерфейсы операционных систем.
• Организация сетей, управление устройствами (модемами) и межпроцес-сное взаимодействие.
• Типы данных и утилиты для типов данных.
• Интерфейсы баз данных.
• Пользовательские интерфейсы.
• Интерфейсы к другим языкам программирования и средства эмуляции этих языков.
• Имена файлов, файловые системы и блокировки файлов (см. также дескрипторы файлов).
• Обработка строк, обработка текстов, синтаксический анализ и поиск.
• Обработка опций, аргументов, параметров и файлов конфигурации.
• Интернационализация и локализация.
• Аутентификация, защита и шифрование.
• World Wide Web, HTML, HTTP, CGI, MIME.
• Серверные утилиты и демоны.
• Архивирование, сжатие и преобразование.
• Изображения, манипулирование картами пикселей и растрами, рисование и построение графиков.
• Электронная почта и телеконференции Usenet.
• Утилиты управления потоком (обратные вызовы и исключительные ситуации).
• Утилиты для работы с дескрипторами файлов, дескрипторами каталогов и потоками ввода-вывода.
• Модули для Microsoft Windows.
• Прочие модули.
DBMбазы данных и DBMхети В большинстве
Библиотека DBM довольно проста, но, учитывая ее доступность, неко-торые системные программы активно используют зту библиотеку для своих довольно скромных нужд. Например, sendmail (а также ее варианты и производные) хранит базу данных aliases (соответствие адресов злектронной почты и имен получателей) как DBM-базу данных. Самое популярнеє ПО телеконференций Usenet использует DBM-базу данных для хранения инфор-мации о текущих и недавно просмотренных статьях. Главные файлы базы данных Sun NTS (урожденной YP) также хранятся в формате DBM.
Per! обеспечивает доступ к такому же механизму DBM довольно умным способом: посредством процесса, похожего на открытие файла, с DBM-базой данных можно связать хеш. Зтот хеш (называемый DBM-массивом) исполь-зуется для доступа к DBM-базе данных и внесення в нее изменений.
Создание нового злемента в зтом массиве влечет за собой немедленное изменение в базе данных. Удаление злемента приводит к удалению значення из DBM-базы данных и т.д.*
Размер, количество и вид ключей и значений в DBM-базе данных ограничены. В зависимости от того, какой версией библиотеки DBM вы пользуетесь, зти же ограничения могут иметь место и для DBM-массива. Подробности см. на man-странице AnyDBM_File. В общем, если вы сумеете сделать так, чтобы и ключи, и значення упаковывались не больше чем в 1000 символов с произвольными двоичными значеннями, то все будет нормально.
Дескрипторы файлов и проверка файлов
Дескрипторы файлов и проверка файлов
Дескрипторы каталогов Если в вашей
Дескриптор каталога представляет собой соединение с конкретным каталогом. Вместо чтения данных (как из дескриптора файла) вы используете дескриптор каталога для чтения списка имен файлов в этом каталоге. Дескрипторы каталогов всегда открываются только для чтения; нельзя использовать дескриптор каталога для изменения имени файла или удаления файла.
Если функции readdir() и ее аналогов в библиотеке нет (и при инсталляции языка Perl никакую замену вы не предусмотрели), то использование любой из этих программ приведет к фатальной ошибке и ваша программа компиляцию не пройдет: она аварийно завершится до выполнения первой строки кода. Perl всегда старается изолировать вас от влияния рабочей среды, но такие чудеса ему не подвластны.
Домашняя страница Perl
Если у вас есть доступ к World Wide Web, посетите домашнюю страницу Perl по адресу http://www.perl.com/perl/. Здесь вы узнаете, что нового произош-ло в мире Perl, сможете получить исходный код и номера портов, докумен-тацию, модули третьих фирм, базу данных ошибок Perl, информацию о списках рассылки и т.д. На этом узле имеется также сервис мультиплек-сирования CPAN, который описан ниже.
Дополнительная литература Естественно
• Файлы документации CGI.pm.
• Библиотека LWP из CPAN.
• CGI Programming on the World Wide Web by Shishir Gundavaram (O'Reilly & Associates).
• Web Client Programming with Perl by Clinton Wong (O'Reilly & Associates).
• HTML: The Definitive Guide by Chuck Musciano and Bill Kennedy (O'Reilly & Associates).
• How to Setup and Maintain a Web Site by Lincoln Stein (Addison-Wesley).
• CGI Programming in С and Perl by Thomas Boutell (Addison-Wesley).
• Сборник FAQ no CGI Ника Кью.
• Man-страницы: perltoot, perlref, perlmod, perlobj.
Дополнительные возможности регулярных выражений
Дополнительные возможности регулярных выражений
Регулярные выражения могут иметь "расширенный" синтаксис (в котором пробельные символы не обязательны, поэтому регулярное выражение может разбиваться на несколько строк и содержать обычные Perl-комментарии), а также иметь положительное и отрицательное "упреждение". Этот синтаксис кажется несколько уродливым, но не пугайтесь и обратитесь к книге Programming Perl или man-странице perlre(l). Все это и многое другое разъясняется в книге Фридла (Friedl) Mastering Regular Expressions (издательство O'Reilly & Associates).
Доступ к каталогам
Доступ к каталогам
Доступ к системным базам данных
Доступ к системным базам данных
Доступность
Доступность
Если при попытке вызвать Perl из sneil вы получите сообщение perl: not found
это значит, что вашего системного администратора еще не охватила Perl-лихорадка. Если язык Perl не инсталлирован в вашей системе, его можно получить бесплатно (или почти бесплатно).
Perl распространяется по открытой лицензии GNU (GNU Public License)*, согласно которой "вы можете распространять двоичные файлы языка Perl только в том случае, если предоставляете исходный код бесплатно, а если вы модифицируете их, вы должны распространять и код этих изменений". По сути дела это означает, что Perl распространяется бесплатно. Его исходный текст можно получить по цене пустой ленты или оплатив стоимость передачи нескольких мегабайтов информации по телефонной линии. При этом никто не может "придержать" сам Perl и послать вам просто двоичные файлы, соответствующие чьему-либо конкретному представлению о "поддерживаемых аппаратных платформах".
По сути дела, Perl не только бесплатен, но и работает достаточно хорошо почти на всем, что называет себя UNIX или UNIX-подобной системой и включает С-компилятор. Это обусловлено тем, что пакет распространяется с адаптивной программой конфигурации, называемой Configure, которая рыщет и шарит по системным каталогам в поисках нужных ей вещей, соответствующим образом корректирует используемые файлы и определенные символы, обращаясь к вам за подтверждением результатов своих изысканий.
Программисты настолько увлеклись языком Perl, что, помимо UNIX- и UNIX-подобных систем, начали использовать его и в системах Amiga, Atari ST, системах семейства Macintosh, VMS, OS/2, даже MS-DOS и, наконец, в Windows NT и Windows 95. К тому моменту, когда вы будете читать эти строки, Perl, вероятно, перенесут и на многие другие системы. Исходные тексты языка Perl (и многие предкомпилированные двоичные файлы для He-UNIX-архитектур) можно получить на одном из серверов сети CPAN (Comprehensive Perl Archive Network). Если вы имеете доступ к World Wide Web, посетите сервер hftp://www.perl.com/CPAN, являющийся одним из множества "зеркальных" (дублирующих) серверов. Если вы абсолютный новичок, отправьте по адресу bookquestions@ora.com послание с вопросом "Где можно получить Perl?!?!" ^Where 1 сап set Perl?!?!").
Или по несколько более либеральной "художественной лицензии" (Artistic License), согласно которой Perl распространяется в виде дистрибутива.
Другие функции
Другие функции
В Perl очень много функций. Мы не собираемся здесь их все перечислять, потому что самый простой способ узнать о них — это прочитать раздел о функциях в книге Programming Perl и man-страницу perlfunc(l). Вот некоторые из наиболее интересных функций.
Функции grep и тар
Функция grep выбирает элементы из списка аргументов на основании результата выражения, которое многократно проверяется на истинность, при этом переменная $_ последовательно устанавливается равной каждому элементу списка:
@bigpowers = grep $_ > 6, 1, 2, 4, 8, 16; # получает (8, 16) @b_names = grep /^Ъ/, qw(fred barney betty wilma) ;
Stextfiles = grep -T, <*>;
Функция map похожа на grep, но вместо выбора и отклонения элементов из списка аргументов она просто выдает результаты вычисления выражения (вычисляемого в списочном контексте):
@more = map $_ + 3, 3, 5, 7; # получает 6, 8, 10 @square s == map $_ * $_, 1. .10; # квадраты первых 10 чисел @that = map "$_\n", Sthis; # как unchop
Ctriangle - map !..$_, 1..5; # 1,1,2,1,2,3,1,2,3,4,1,2,3,4,5 %sizes = map ( $_, -s ) <*>; # хеш файлов и размеров
Операция eval (и
s///e)Да, вы можете создать фрагмент кода во время работы программы и выполнить его при помощи функции eval точно так же, как в shell. Это по-настоящему полезная возможность, благодаря которой можно выполнить оптимизацию периода компиляции (например, получить компилированные регулярные выражения) во время выполнения. С ее помощью можно также вылавливать во фрагменте кода ошибки, которые в противном случае будут фатальными: фатальная ошибка внутри eval просто приводит к выходу из этой функции и выдает пользователю код ошибки.
Вот, например, программа, которая читает строку Perl-кода, вводимую пользователем, а затем выполняет ее так, как будто это часть Perl-программы:
print "code line: ";
choptScode = <STDIN” ;
eval $code; die "eval: $@" if $@;
Perl-код можно вставить в заменяющую строку при выполнении операции замены с помощью флага е. Это удобно, если вы хотите включить в заменяющую строку нечто сложное, например, вызов подпрограммы, которая возвращала бы результаты поиска в базе данных. Вот цикл, который инкрементирует значение первой колонки для ряда строк:
while (о) (
s/"
(\S+)/$l+l/e; f $1+1 is Perl code, not a stringprintf;
}
Функция evai используется также как механизм обработки исключений:
eval {
some_hairy_routine_that_might_die(Oargs);
};
if ($0) (
print "oops... some_hairy died with $@";
1
Здесь массив $@ пуст до тех пор, пока блок eval работает нормально, а в противном случае этот блок выдает "сообщение о смерти".
Из этих трех конструкций (eval "строка", eval { БЛОК } и s///e) только первая действительно соответствует вашим представлениям об eval из shell. Остальные две компилируются "на ходу", что влечет за собой незначительное снижение производительности.
Другие книги
Programming Perl — полный справочник по Perl, тогда как нашу книгу скорее можно назвать пособием. Если вы хотите больше узнать о регулярных выражениях, используемых в Perl, предлагаем вам книгу Mastering Regular Expressions by Jeffrey E.F. Friedl (O'Reilly & Associates).
Посмотрите также вышедшие в издательстве O'Reilly & Associates книги CGf Programming on the World Wide Web by Shishir Gundavaram; Web Client Programming with Perl by Clinton Wong; HTML: The Definitive Guide by Chuck Musciano and Bill Kennedy.
Книги The AWK Programming Language by Aho, Kernighan, and Weinberger (Addison-Wesley) и sed &. awk by Dale Dougherty (O'Reilly & Associates) содержат обширный базовый материал по таким вопросам, как ассоциатив-ные массивы, регулярные выражения и общее мировоззрение, благодаря которому появился Perl. В них приведено множество примеров, которые можно перевести на Perl с помощью конвертора awk-to-perl (а2р) или конвертора sed-to-perl (s2p). Конечно, эти конверторы не выдают совершен-ный Perl-код, но если вы не сможете реализовать один из этих примеров в Perl, выходная информация конвертора даст вам хорошую подсказку.
Для Web-мастеров мы рекомендуем второе издание книги How to Setup and Maintain a Web Site by Lincoln Stein (Addison Wesley). Д-р Штейн, известный как автор Perl-модуля CGI.pm (см. главу 19), профессионально и всесторонне рассматривает все вопросы, связанные с администрированием Web-узла на платформах UNIX, Mac и Windows.
Мы также рекомендуем удобный и тщательно проработанный краткий справочник Perl 5 Desktop Reference by Johan Vromans (O'Reilly & Associates).
Другие компоненты формы Теперь
Сейчас мы рассмотрим более развитую версию нашей программы. В частности, мы включили в нее новые компоненты формы: всплывающие меню, кнопку передачи (которая называется order) и кнопку очистки полей формы, позволяющую стереть все данные, введенные пользователем. Всплывающие меню делают именно то, о чем говорят их имена, но аргументы, указанные в popup_menu, могут озадачить вас — пока вы не прочитаете следующий раздел, "Ссылки". Функция textfieldO создает поле для ввода текста с указанным именем. Подробнее об этой функции мы расскажем ниже, когда будем описывать программу гостевой книги.
#!/usr/local/bin/perl5 -w
# программа ответа на форму заказа мороженого и генерирования этой формы (версия 4) use strict;
# ввести объявления переменных и выполнить заключение в кавычки use CGI qw(:standard);
print header;
print start html("Ice Cream Stand"), hi ("Ice Cream Stand");
if (paramO) ( # форма уже заполнена
my $who = param("name");
my $flavor = param("flavor");
my $scoops = param("scoops");
my $taxrate = 1.0743;
my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops * 0.25));
print p("0k, $who, have $scoops scoops of $flavor for \$$cost.");
}
else ( # первый проход, представить незаполненную формуprint hr() ;
print start_form();
print p("What's your name? ",textfield("name"));
print p("What flavor: ", popup_menu("flavor",
['mint','cherry','mocha']));
print p("How many scoops? ", popup_menu("scoops", [1..3]));
print p(submit("order"), reset("clear"));
print end_form(), hr();
} print end_html;
На Рисунок 19.4 представлено изображение начальной формы, которую создает рассматриваемая программа.
Ice Cream Stand
What's your name? |
What flavor: |t"ii4 How many scoops? 11
Рисунок 19.4. Более сложная форма
Как вы помните, функция param() при вызове ее без аргументов возвращает имена всех полей формы, которые были заполнены. Таким образом вы можете узнать, была ли заполнена форма перед вызовом программы. Если у вас есть параметры, это значит, что пользователь заполнил некоторые поля существующей формы, поэтому на них нужно ответить. В противном случае следует генерировать новую форму с расчетом на вторичный вызов той же самой программы.
Ссылки
Вы, возможно, заметили, что обе функции popup_menu () в предыдущем примере имеют весьма странные аргументы. Что означают [ 'mint', 'cherry' , 'mocha' ] и [ 1. . 3 ] ? Квадратные скобки создают нечто такое, с чем вы раньше не встречались: ссылку на анонимный массив. Это обусловлено тем, что функция popup_menu () в качестве аргумента рассчитывает получить именно ссылку на массив. Другой способ создания ссылки на массив — использовать перед именованным массивом обратную косую черту, например \@choices. Так, следующий фрагмент кода:
@choises = ('mint',"cherry','mocha');
print pC'What flavor: ", popup_menu ("flavor", \@choises));
работает так же хорошо, как этот:
print pC'What flavor: ", popup_menu ("flavor", ['mint','cherry','mocha']));
Ссылки функционируют примерно так, как указатели в других языках, но с меньшей вероятностью появления ошибок. Они представляют собой значения, которые указывают на другие значения (или переменные). Ссылки Perl строго делятся на типы (без возможности приведения типов) и никогда не вызывают вывода дампов ядра операционной системы. Более того, если область памяти, на которую указывают ссылки, больше не используется, она автоматически возвращается в использование. Ссылки'играют центральную роль в объектно-ориентированном программировании. Они применяются и в традиционном программировании, являясь основой для создания структур данных, более сложных, нежели простые одномерные массивы и хеши. Язык Perl поддерживает ссылки как на именованные, так и на анонимные скаляры, массивы, хеши и функции.
Также, как методом \@массив можно создавать ссылки на именованные массивы и посредством указания [ список ] — на анонимные хеши, можно методом \%хеш создавать ссылки на именованные хеши, а методом
( ключ1, значение!, ключ2, значение2, ... }
— на анонимные*.
Да, фигурные скобки теперь используются в Perl с различными целями. Их функцию определяет контекст, в котором используются фигурные скобки.
Подробнее о ссылках вы прочитаете в главе 4 книги Programming Perl и на man-странице perlref(l).
Более сложные вызывающие последовательности
Мы закончим наш рассказ о компонентах форм созданием одного очень полезного компонента, который позволяет пользователю выбирать любое число элементов этого компонента. Функция scrolling_list () модуля CGI.pm может принимать произвольное число пар аргументов, каждая из которых состоит из именованного параметра (начинающегося со знака -) и значения этого параметра.
Чтобы ввести в форму прокручиваемый список, нужно сделать следующее:
print scrolling_list(
-NAME => "flavors",
-VALUES => [ qw(mint chocolate cherry vanilla peach) ],
-LABELS => {
mint => "Mighty Mint",
chocolate => "Cherished Chocolate",
cherry => "Cherry Cherry",
vanilla => "Very Vanilla",
peach => "Perfectly Peachy", },
-SIZE =>3,
-MULTIPLE => 1, tl for true , 0 for false
Значения параметров имеют следующий смысл:
-NAME
Имя компонента формы. Значение этого параметра можно использовать позже для выборки пользовательских данных из формы с помощью функции param().
-LABELS
Ссылка на анонимный хеш. Значения хеша — это метки (элементы списка), которые видит пользователь формы. Когда пользователь выбирает ту или иную метку, в CGI-программу возвращается соответствующий ключ хеша. Например, если пользователь выбирает элемент, заданный как Perfectly Peachy, CGI-программа получает аргумент peach.
-VALUES
Ссылка на анонимный массив. Этот массив состоит из ключей хеша, на которые ссылается -labels.
-SIZE
Число, определяющее, сколько элементов списка пользователь будет видеть одновременно.
-MULTIPLE
Истинное или ложное значение (в том смысле, который принят для этих понятий в Perl), показывающее, можно ли будет пользователю формы выбирать более одного элемента списка.
Если -multiple установлена в значение "истина", вы можете присвоить список, возвращаемый функцией param(), массиву:
@choices = param("flavors");
Вот другой способ создания этого прокручиваемого списка — с передачей ссылки на существующий хеш вместо создания такого хеша "на ходу":
%flavors = (
"mint", "Mighty Mint",
"chocolate", "Cherished Chocolate",
"cherry", "Cherry Cherry",
"vanilla", "Very Vanilla",
"peach", "Perfectly Peachy",
);
print scrolling list(
-NAME => "flavors",
-LABELS => \%flavors,
-VALUES => [ keys %flavors ],
-SIZE => 3,
-MULTIPLE => 1, #1 for true , 0 for false ) ;
На этот раз мы передаем в функцию значения, вычисленные по ключам хеша %flavors, ссылка на который выполняется с помощью операции \, Обратите внимание: параметр -values здесь тоже взят в квадратные скобки. Простая передача результата операции keys в виде списка не сработает, потому что в соответствии с правилом вызова функции scrolling_list() должна быть сделана ссылка на массив, которую как раз и создают квадратные скобки. Считайте квадратные скобки удобным способом представления нескольких значений как одного.
Другие операции
Другие операции
Помимо упомянутых в книге, используются и другие операции. Например, операция "запятая". Есть также операции манипулирования битами &, I, л и ~, трехместная операция ?\ :, операции . . и ... и другие.
Имеются также вариации операций, например, допускается использование модификатора д в операции сопоставления. Об этом и многом другом рассказывается на man-странице perlop(l).
Другие операции преобразования данных
Другие операции преобразования данных
Еще о поледержателяж
Еще о поледержателяж
Из примеров вы уже поняли, что поледержатель @““ обозначает выровненное по левому краю поле, которое содержит пять символов, а @“““““ — выровненное по левому краю поле, содержащее одиннадцать символов. Как мы и обещали, опишем поледержатели более подробно.
Текстовые поля
Большинство поледержателей начинается со знака @. Символы, стоящие после него, обозначают тип поля, а число этих символов (включая @) соответствует ширине поля.
Если после знака @ стоят левые угловые скобки (““), поле выровнено по левому краю, т.е. в случае, если значение окажется короче, чем отведенное для него поле, оно будет дополняться справа символами пробела. (Если значение слишком длинное, оно автоматически усекается; структура формата всегда сохраняется.)
Если после знака @ стоят правые угловые скобки (””), поле выровнено по правому краю, т.е. в случае, если значение окажется короче, чем отведенное для него поле, оно будет заполняться пробелами слева.
Наконец, если символы, стоящие после знака @, — повторяющаяся несколько раз вертикальная черта (||||), то поле центрировано. Это означает, что если значение слишком короткое, производится дополнение пробелами с обеих сторон, в результате значение будет расположено по центру поля.
Числовые поля
Следующий тип поледержателя — числовое поле с фиксированной десятичной запятой, полезное для больших финансовых отчетов. Это поле также начинается со знака @; за ним следует один или более знаков # с необязательной точкой (она обозначает десятичную запятую). Опять-таки, знак @ считается одним из символов поля. Например:
format MONEY =
Assets: @#W#.*” Liabilities: @#*”##.*# Net: @t”##*.*#
$assets, $liabilities, $assets-$liabilities
Эти три числовых поля предусматривают шесть знаков слева от десятичной запятой и два справа (в расчете на суммы в долларах и центах). Обратите внимание на то, что в формате используется выражение — это абсолютно допустимо и встречается очень часто.
Ничего оригинального в Perl больше нет: вам не удастся установить формат с плавающей запятой для вывода значений денежных сумм, нельзя также заключить отрицательные значения или что-нибудь подобное в квадратные скобки. Для этого придется писать отдельную программу, например:
format MONEY =
Assets: @“““<“ Liabilities: @““““ Net: @““<““
&cool($assets,10), scool($liab,9), Scool($assets-$liab,10)
sub pretty (
my($n,$width) = @_;
$width -— 2; # учтем отрицательные числа
$n ° sprintf("%.2f",$n); # sprintf описывается в одной из следующих глав if ($n < 0) (
return sprintf ("[t$width.2f]", -$n); # отрицательные числа
# заключаются в квадратные скобки ) else {
return sprintf (" %$width.2f ", $n); # положительные числа выделяются
^
пробелами } }## body of program:
$assets = 32125.12;
$liab = 45212.15;
write (MONEY) ;
Многостроковые поля
Как уже упоминалось выше, при подстановке значения, содержащегося в строке значений. Perl обычно заканчивает обработку строки, встретив в этом значении_символ новой строки. Многостроковые поледержатели позволяют использовать значения, которые представляют собой несколько строк информации. Эти поледержатели обозначаются комбинацией @*, которая ставится в отдельной строке. Как всегда, следующая строка определяет значение, подставляемое в это поле. В данном случае это может быть выражение, которое дает в результате значение, содержащее несколько строк. Подставленное значение будет выглядеть так же, как исходный текст:
четыре строки значения становятся четырьмя строками выходной информации. Например, приведенный ниже фрагмент программы
format STDOUT = Text Before. @*
$long_string Text After.
$long_string = "Fred\nBarney\nBetty\nWilma\n";
write;
позволяет получить такие выходные данные:
Text Before.
Fred
Barney
Betty
Wilma
Text After.
Заполненные поля
Следующий вид поледержателя — заполненное поле. Этот поледержатель позволяет создавать целый текстовый абзац, разбиение на строки которого выполнено по границам слов. Для этого используются несколько элементов формата, которые работают в совокупности. Но давайте рассмотрим их по отдельности.
Во-первых, заполненное поле обозначается путем замены маркера @ в текстовом поледержателе на символ А (например, /'<“). Соответствующее значение для заполненного поля (в следующей строке формата) должно быть скалярной переменной*, содержащей текст, а не выражением, которое возвращает скалярное значение. Это объясняется тем, что при заполнении этого поледержателя Perl изменяет значение переменной, а значение выражения изменить очень трудно.
Когда Perl заполняет данный поледержатель, он берет значение этой переменной и "захватывает" из него столько слов (подразумевая разумное определение термина "слово")**, сколько поместится в этом поле. Эти слова фактически "выдираются" из переменной; после заполнения поля значение переменной представляет собой то, что осталось после удаления слов. Почему делается именно так, вы скоро увидите.
* А также отдельным скалярным элементом массива или хеша, например, $а[3] или $h{"fred").
** Разделители слов задаются переменной $:.
Пока что особой разницы между заполненным полем и обычным текстовым полем не видно; мы выводим в поле ровно столько слов, сколько в нем умещается (за исключением того, что мы соблюдаем границу последнего слова, а не просто обрезаем текст по ширине поля). Удобство использования заполненного поля проявляется, когда в одном формате делается несколько ссылок на одну переменную. Взгляните на этот пример:
format PEOPLE =
Name: @<““““““ Comment: "““““““““““^“““^ $name, $comment
$comment $comment $comment
Обратите внимание: переменная $ comment появляется четыре раза. Первая строка (строка с полем имени) выводит имя и первые несколько слов значения этой переменной. В процессе вычисления этой строки $ comment изменяется так, что эти слова исчезают. Вторая строка опять ссылается на ту же переменную ($comment) и поэтому получает из нее следующие несколько слов. Это справедливо и для третьей, и для четвертой строк. По сути дела, мы создали прямоугольник, который будет максимально заполнен словами из переменной $ comment, расположенным в четырех строках.
Что будет, если полный текст занимает меньше четырех строк? Получатся одна-две пустые строки. Это, наверно, нормально, если вы печатаете этикетки и вам нужно, чтобы в каждом элементе было одинаковое количество строк. Если же вы печатаете отчет, наличие множества пустых строк приведет к неоправданному расходу бумаги.
Чтобы решить эту проблему, нужно использовать признак подавления. Строка, содержащая тильду (~), подавляется (не выводится), если при печати она окажется пустой (т.е. будет содержать только пробельные символы). Сама тильда всегда печатается как пробел и может ставиться в любом месте строки, в котором можно было бы поставить пробел. Перепишем последний пример так:
format PEOPLE = Name: @““““““< Comment: ^“““““““““““““x
$name, $comment
$comment $comment $comment
Теперь, если комментарий занимает всего две строки, третья и четвертая строки будут автоматически подавлены.
Что будет, если комментарий занимает больше четырех строк? Мы могли бы сделать около двадцати копий последних двух строк этого формата, надеясь, что двадцати строк хватит. Это, однако, противоречит идее о том, что Perl помогает лентяям, поэтому специально для них предусмотрено следующее: любая строка, которая содержит две рядом стоящие тильды, автоматически повторяется до тех пор, пока результат не будет полностью пустой строкой. (Эта пустая строка подавляется.) В итоге наше определение формата приобретает такой вид:
format PEOPLE = Name: @<““““““ Comment: ^“““““““““““““^
$name, $comment
$comment
Таким образом, все будет нормально, сколько бы строк ни занимал комментарий — одну, две или двадцать.
Отметим, что данный критерий прекращения повторения строки требует, чтобы в некоторый момент данная строка стала пустой. Это значит, что в этой строке не нужно размещать постоянный текст (кроме символов пробела и тильд), иначе она никогда не станет пустой.
Еще об операции сопоставления
Выбор другого объекта для сопоставления (операция :='•)
Обычно строка, которую нужно сопоставить с образцом, не находится в переменной $_, и помещать ее туда довольно утомительно. (Может быть, в переменной $__ уже хранится значение, которое вам не хочется терять.) Ничего страшного — здесь нам поможет операция =~. С ее помощью вы можете назначить для проведения операции сопоставления строку, хранящуюся в переменной, отличной от $_.
Эта переменная указывается справа от знака операции. Выглядит это так:
$а = "hello world";
$а =~ /^he/; # истина
$а =~ /(.)\1/; # тоже истина (соответствует двум 1)
if ($а =~ /(.)\1/) ( t истина, поэтому проводятся дальнейшие операции
1
Справа от знака операции =~ может стоять любое выражение, которое дает в результате некоторое скалярное строковое значение. Например, <stdin> при использовании в скалярном контексте дает скалярное строковое значение, поэтому, объединив эту операцию с операцией =~ и операцией сопоставления с регулярным выражением, мы получим компактную программу проверки входных данных:
print "any last request? ";
if (<STDIN> ==~ /л[y1}/) { # начинаются ли входные данные с буквы у? print "And just what might that request be? ";
# и чтобы это мог быть за запрос? <STDIN>; # получить строку со стандартного ввода print "Sorry, I'm unable to do that.\n";
# прошу прощения, но я не могу этого сделать )
В данном случае при помощи <stdin> берется очередная строка со стандартного ввода, которая затем сразу же используется как строка, сопоставляемая с образцом л [ yY ]. Отметим, что мы не сохраняли входные данные в переменной, поэтому если мы захотим сопоставить эти данные с другим образцом или же вывести их в сообщении об ошибке, то у нас ничего не выйдет. Тем не менее эта форма часто оказывается удобной.
Игнорирование регистра
В предыдущем примере мы указывали образец [yY] для обозначения строчной и прописной буквы у. Если речь идет об очень коротких строках, например, у или fred, то данный способ обозначения достаточно удобен, скажем, [fF] [rR] [eE] [dD]. А что делать, если сопоставляемая строка — это слово procedure в нижнем или верхнем регистре?
В некоторых версиях grep флаг -i означает "игнорировать регистр". В Perl тоже есть такая опция. Чтобы ею воспользоваться, нужно добавить строчную i к закрывающей косой черте, т.е. написать / образец/i. Такая запись говорит о том, что буквы образца будут соответствовать буквам строки в любом регистре. Например, чтобы найти слово procedure в любом регистре, стоящее в начале строки, запишите /^procedure/i.
Теперь наш предыдущий пример будет выглядеть так:
print "any last request? ";
if (<STDIN> =~ /"y/i) { # начинаются ли входные данные с буквы у? # да! выполнить какие-то операции
…
}
Использование другого разделителя
Чтобы найти строку, которая содержит несколько косых (/), в соответствующем регулярном выражении нужно перед каждой из них поставить обратную косую черту (\). Например, чтобы найти строку, которая начинается с названия директории /usr/etc, нужно записать:
$path = <STDIN>; # прочитать путевое имя (вероятно, из find?) if ($path =~ /"VusrVetc/) {
# начинается с /usr/etc... }
Как видите, комбинация "обратная косая — косая" создает между элементами текста своеобразные "проходы". Если косых очень много, это занятие может стать весьма утомительным, поэтому в Perl предусмотрена возможность использования другого разделителя (delimiter). Поставьте перед любым специальным символом* (выбранным вами в качестве разделителя) букву т, укажите свой образец и дайте еще один такой же разделитель:
/''•VusrVetc/ # использование стандартного разделителя — косой черты m@^/usr/etc@ # использование в качестве разделителя символа @ m#^/usr/etc# # использование в качестве разделителя символа # # (это мой любимый символ)
Если хотите, можете опять использовать косые, например, m/fred/. Таким образом, m — общепринятое обозначение операции сопоставления с регулярным выражением, но если в качестве разделителя выбрана косая черта, то m не обязательна.
Использование интерполяции переменных
Перед тем как регулярное выражение рассматривается на предмет наличия специальных символов, в нем производится интерполяция переменных. Следовательно, регулярное выражение можно строить не только из литералов, но и из вычисляемых строк. Например:
$what = "bird";
$sentence = "Every good bird does fly.";
if ($sentence =~ /\b$what\b/) {
print "The sentence contains the word $what!\n";
>
Здесь мы использовали ссылку на переменную для построения операции сопоставления с регулярным выражением \bbird\b/.
* Если этот разделитель — левый элемент пары (круглая, фигурная, угловая или квадратная скобка), то закрывающим разделителем будет соответствующий правый элемент пары. В остальных случаях первый и второй разделители будут совпадать.
Вот несколько более сложный пример:
$sentence = "Every good bird does fly.";
print "What should I look for? ";
$what = <STDIN>;
chomp($what) ;
if ($sentence =~ /$what/) ( # нашли! print "I saw $what in $sentence.\n";
} else (
print "nope... didn't find it.\n";
)
Если вы введете слово bird, оно будет найдено, а если слово scream — не будет. Если ввести [bw] ird, результаты поиска тоже будут успешными. Это говорит о том, что квадратные скобки в данном случае воспринимаются как символы сопоставления с образцом.
Чтобы избежать этого, следует поставить перед этими символами обратную косую, которая превратит их в символы буквального сопоставления. Это кажется сложным, если в вашем распоряжении нет закавычивающей управляющей последовательности \Q:
$what = "[box]";
foreach (qw(in([box] out [box] white [sox] ) ) { if (/\Q$what\E/) {
print "$_ matched!\n";
1 }
Здесь конструкция \Q$what\E превращается в \[box\], в результате чего операция сопоставления ищет пару квадратных скобок, а не рассматривает всю конструкцию как класс символов.
Специальные переменные, защищенные от записи
После успешного сопоставления с образцом переменным $1, $2, $3 и т.д. присваиваются те же значения, что и \1, \2,\3 и т.д. Это можно использовать для поиска соответствия в последующем коде. Например:
$_ = "this is a test";
/(\w+)\W+(\w+)/; # сопоставление первых двух слов
# $1 теперь содержит this, а $2 — is
Доступ к тем же значениям ($1, $2, $3 и т.д.) можно также получить, использовав операцию сопоставления для соответствующих списков. Если результаты сопоставления окажутся положительными, будет получен список значений от $1 до $п (где n — количество занесенных в память элементов). В противном случае значения не определены. Запишем последний пример по-другому:
$_ = "this is a test";
($first, $second) = /(\w+)\W+(\w+)/; # сопоставление первых двух слов # $first теперь содержит this, a $second - is
К другим предопределенным защищенным от записи переменным относятся: $& (часть строки, совпавшая с регулярным выражением); $' (часть строки, стоящая перед совпавшей частью); $ ' (часть строки, стоящая после совпавшей части). Например:
$_ = "this is a sample string";
/sa.*le/; # соответствует слову sample внутри строки
# $' теперь содержит "this is a "
# $& теперь содержит "sample"
# $' теперь содержит "string"
Поскольку значения этим переменным присваиваются при каждом успешном сопоставлении, их нужно где-нибудь сохранить, если они вам впоследствии понадобятся*.
Формат начала страницы Многие
Perl позволяет определять специальный формат начала страницы, с помощью которого запускается режим постраничной обработки. Perl подсчитывает все выходные строки, генерируемые при вызове формата для конкретного дескриптора файла. Если следующая строка не умещается на оставшейся части текущей страницы, Perl выдает символ перехода на новую страницу, за которым автоматически следует вызов формата начала страницы и текст, который выводится с использованием формата для конкретного дескриптора файла. Благодаря этому текст, полученный в результате одного вызова функции write, никогда не разбивается на несколько страниц (если только он не настолько велик, что не помещается на одной странице).
Формат начала страницы определяется так же, как и всякий другой формат. Имя формата начала страницы для конкретного дескриптора файла по умолчанию состоит из имени этого дескриптора и символов _тор (обязательно прописных).
Переменная $% в Perl определяется как количество вызовов формата начала страницы для конкретного дескриптора файла, что позволяет использовать эту переменную в составе формата начала страницы для нумерации страниц. Например, добавление следующего определения формата в предыдущий фрагмент программы предотвращает разрыв адресной этикетки на границах страниц и обеспечивает указание текущего номера страницы:
format ADDRESSLABEL_TOP = My Addresses -- Page @< $%
Длина страницы по умолчанию — 60 строк. Этот параметр можно изменить, присвоив значение специальной переменной, о которой вы вскоре узнаете.
Perl не замечает, если вы выполняете для этого же дескриптора файла функцию print из другого места в программе, вследствие чего число строк, которые можно разместить на текущей странице, уменьшается. Вам следует либо переписать свой код, чтобы с помощью одних и тех же форматов выводить на печать всю информацию, либо после выполнения print изменить переменную "число строк на текущей странице". Через минуту мы увидим, как можно изменить это значение.
Форматирование данных с помощью
$result = sprintf("X%05d",$y);
Описание аргументов функции sprintf вы найдете в разделе sprintf главы 3 книги Programming Perl и на man-странице printf(3) (если она у вас єсть).
Форматы
Форматы
FTP
Чтобы использовать FTP, вам понадобится компьютер, имеющий непо-средственный выход в Internet. Ниже приведен пример сеанса связи.
% ftp ftp.ora .corn Connected to ftp.uu.net
220 ftp.ora.corn FTP server (Version 6.34 Thu Oct 22 14:32:01 EDT 1992)ready. Name (ftp. ora. com:username) : anonymous 331 Guest login ok, send e-mail address as password. Password: username@hostname
(здесь используйте свое пользовательское имя и хост-имя)
230 Guest login ok, access restrictions apply. ftp> cd /published/oreilly/nu-tshell/learn3.ng_Jperl2 250 CWD command successful. ftp> get README
200 PORT command successful.
150 Opening ASCII mode data connection for README (xxxx bytes). 226 Transfer complete. local: README remote: README
xxxx bytes received in xxx seconds (xxx Kbytes/s) ftp> binary 200 Type set to 1. ftp> get examples, tar.gz 200 PORT command successful.
150 Opening BINARY mode data connection for examples.tar.gz (xxxx DycesJ. 226 Transfer complete, local; exercises remote: exercises xxxx bytes received in xxx seconds (xxx Kbytes/s) ftp> quit 221 Goodbye.
FTPMAIL
FTPMAIL — это почтовый сервер, доступный каждому, кто имеет воз-можность посылать электронную почту на узлы Internet и получать ее оттуда. Доступ к FTPMAIL обеспечивают все провайдеры Internet, предоставляющие услуги электронной почты. Вот как это можно сделать.
Вы посылаете почту HQ.y3enftpmail@online.ora.com. В теле сообщения дайте FTP-команды, которые хотите выполнить. Сервер запустит для вас FTP-сеанс от имени анонимного пользователя и пошлет вам необходимые файлы. Чтобы получить полный справочный файл, пошлите сообщение без указания темы и с телом, состоящим из одного слова — help. Ниже приведен пример сеанса работы с электронной почтой в UNIX, в ходе которого пользователь получает программы-примеры. Эта команда посылает вам перечень файлов, имеющихся в текущем каталоге, и затребованные файлы примеров. Данный перечень полезен, если существуют более поздние версии примеров, которые вас интересуют.
(на какой компьютер вы хотите принять файлы)
open cd /published/oreilly/nutahell/learning_perl2 dir get README mode binary uuencode get examples, tar.gz quit
Подпись в конце сообщения приемлема, если она стоит после команды quit.
Функции
Функции
Мы уже знакомы со встроенными пользовательскими функциями, например chomp, print и другими, и пользовались ими. Теперь давайте рассмотрим функции, которые вы можете определить сами.
Функции split и join Регулярные
Функция split
Функция split получает регулярное выражение и строку и ищет в этой строке все экземпляры указанного регулярного выражения. Те части строки, которые не совпадают с регулярным выражением, возвращаются по порядку как список значений. Вот, например, код синтаксического анализа разделенных двоеточиями полей, аналогичных тем, которые используются в UNIX-файлах /etc/passwd:
$line = "merlyn::118:10:Randal:/home/merlyn:/usr/bin/peri";
@fields = split (/:/,$line); # разбить $line, используя в качестве t разделителя двоеточие
# теперь @fields содержит ("merlyn","","118","10",
# "Randal","/home/merlyn","/usr/bin/peri")
Обратите внимание на то, что второе пустое поле стало пустой строкой. Если вы этого не хотите, задайте сопоставление следующим образом:
Sfields = split(/:+/, $line);
Здесь при сопоставлении принимаются во внимание одно и более расположенных рядом двоеточий, поэтому пустое поле не образуется.
Очень часто приходится разбивать на поля значение переменной $_, поэтому этот случай предлагается по умолчанию:
$ = "some string";
Swords = split (/ /); # то же самое, что и Swords = split(/ /, $_); *
# Или две пары, если используется символ из пары "левая-правая".
При такой разбивке соседние пробелы в разбиваемой строке вызовут появление пустых полей (пустых строк). Лучше использовать образец / +/, а лучше /\s+/, который соответствует одному и более пробельным символам. Этот образец, по сути дела, используется по умолчанию*, поэтому, если вы разбиваете переменную $_ по пробельным символам, вы можете использовать все стандартные значения и просто написать :
Swords = split; # то же самое, что и (Swords = split(/\s+/, $_) ;
Завершающие строки пустые поля в список, как правило, не включаются. Особой роли это обычно не играет. Решение вроде
$line = "merlyn::118:10:Randal:/home/merlyn:";
($name,$password,$uid,$gid,$gcos,$home,$shell) = split(/:/,$line);
# разбить $line, используя в качестве разделителя двоеточие
просто присваивает переменной $shell нулевое значение (undef), если эта строка недостаточно длинна или содержит в последнем поле пустые значения. (Разбиение выполняется так, что лишние поля просто игнорируются.)
Функция join
Функция join берет список значений и "склеивает" их, ставя между элементами списка строку-связку. Выглядит это так:
$bigstring = join($glue,@list);
Например, чтобы восстановить строку пароля, попробуйте использовать следующее:
$outline = join(":", @fields) ;
Отметим, что строка-связка — это не регулярное выражение, а обычная строка, состоящая из символов общим числом нуль или более.
Если нужно поставить связку не между элементами, а перед каждым элементом, то достаточно такого трюка:
$result = (join "+", "", @fields);
Здесь пустая строка "" рассматривается как пустой элемент, который должен быть связан с первым элементом данных массива @fields.B результате связка помещается перед каждым элементом. Аналогичным образом можно поставить пустой элемент-связку в конец списка:
$output = join ("\n", @data, "");
* На самом деле образец по умолчанию — строка "", поэтому начальный пробельный разделитель игнорируется, но для нас вышесказанного пока достаточно.
Функции stat и Istat
Функции stat и Istat
Вышеупомянутые операции весьма эффективны при проверке различных атрибутов конкретного файла или дескриптора файла, но полную информацию с их помощью получить нельзя. Например, не предусмотрена операция проверки, которая возвращала бы число ссылок на файл. Чтобы добраться до остальных сведений о файле, вызовите функцию stat, которая возвращает практически все, что возвращает системный вызов stat в POSIX (надеемся, мы сказали больше, чем вы хотите знать).
Операнд функции stat — дескриптор файла или выражение, посредством которого определяется имя файла. Возвращаемое значение — либо undef, если вызов неудачен, либо 13-элементный список**, который легче всего описать с помощью такого списка скалярных переменных:
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev, $size, $atinie, $mtime, $ctime, $blksize,$blocks) = stat (. . .)
* Или операцию int.
** Если вам тяжело запомнить порядок значений, возвращаемых функцией stat, можете обратиться к модулю File: :stat, впервые введенному в выпуске 5.004. Он обеспечивает доступ к этим значениям следующим образом:
$file_owner = stat($filename)->uid
Имена здесь соответствуют частям структуры stat, подробно описанной на man-странице stat(T). Рекомендуем изучить приведенные там подробные пояснения.
Например, чтобы получить идентификаторы пользователя и группы из файла паролей, нужно записать:
($uid,,$gid) = (stat("/etc/passwd")) [4,5];
и этого окажется достаточно.
Вызов функции stat с именем символической ссылки возвращает информацию о том, на что указывает эта ссылка, а не сведения о самой ссылке (если только она не указывает на что-то в текущий момент недоступное). Если вам нужна информация о самой символической ссылке (большей частью бесполезная), используйте вместо stat функцию istat (которая возвращает те же данные в том же порядке). С элементами, которые не являются символическими ссылками, функция istat работает аналогично stat.
Как и в операциях проверки файлов, операнд функций stat и Istat по умолчанию — $_. Это значит, что операция stat будет выполняться над файлом, заданным скалярной переменной $_.
Где найти упражнения
Упражнения, приведенные в этой книге, можно получить в электронном варианте разными способами: по FTP, FTPMAIL, BITFTP и UUCP. Самые дешевые, самые быстрые и самый легкие способы указаны первыми. Если читать сверху вниз, то самый лучший метод — это, вероятно, первый из тех, которые работают. При непосредственной работе в Internet используйте FTP. Если у вас нет прямого соединения с Internet, но вы можете посылать электронную почту на узлы Internet и получать ее с этих узлов, используйте FTPMAIL. Если вы посылаете электронную почту по BITNET, используйте BITFTP. Если ни один из этих способов не действует, используйте UUCP.
Примечание: упражнения разрабатывались с помощью UNIX-системы. Если вы работаете в среде UNIX, можете использовать их, не корректируя. При работе на другой платформе эти упражнения, возможно, придется слегка модифицировать. Например, при работе с UNIX каждая строка завершается символом новой строки (возврат каретки подразумевается), тогда как в DOS каждая строка должна завершаться явно указанными символами и новой строки, и возврата каретки. В зависимости от конфигурации вашей системы и используемого метода пересылки упражнений по сети вам, возможно, придется добавить символы возврата каретки. Дополнительную информацию по этому вопросу можно найти в файле README, который прилагается к упражнениям.
Генерирование формы
Генерирование формы
Если вам надоело вводить параметры своей программы в броузер — создайте заполняемую форму. К таким формам привыкли большинство пользователей. Компоненты формы, которые принимают вводимые пользователем данные, иногда называются vidgets; считается, что этот термин гораздо удобнее, чем "устройства графического ввода". Такие компоненты форм включают одно- и многостроковые текстовые поля, всплывающие меню, прокручиваемые списки, различные виды кнопок и отмечаемых блоков.
Создайте следующую HTML-страницу, которая включает форму с одним компонентом "текстовое поле" и кнопкой передачи. Когда пользователь щелкает на кнопке передачи*, вызывается сценарий ice_cream, заданный атрибутом ACTION.
<!-- ice_cream.html —> <HTML>
<HEAD>
<TITLE>HeUo Ice Cream</TITLE>
</HEAD>
<BODY>
<Hl>Hello Ice Cream!</Hl>
<FORM ACTION-"http://www.SOMEWHERE.org/cgi-bin/ice_cream">
What's your flavor? <INPUT NAME="favorite" VALUE="mint">
<P>
<INPUT TYPE="submit">
</FORM>
</BODY> </HTML>
Помните, что CGI-программа может выдавать ту выходную HTML-информацию, которую вы ей укажете. Эта информация будет затем передаваться в тот броузер, который обратится к URL данной программы. CGI-программа может, таким образом, не только реагировать на данные, введенные пользователем в форму, но и генерировать HTML-страницу с формой. Более того, одна программа может выполнять одну за другой обе эти задачи. Все, что вам нужно сделать,— это разделить программу на две части, которые делают разные вещи в зависимости от того, была ли программа вызвана с аргументами или нет. Если аргументов не было, программа посылает в броузер пустую форму; в противном случае аргументы содержат данные, введенные пользователем в ранее переданную форму, и программа возвращает в броузер ответ на основании этих данных.
* Некоторые броузеры позволяют обходиться без кнопки передачи, если форма содержит только одно поле для ввода текста. Если курсор находится в этом поле и пользователь нажимает клавишу [Enter], это считается запросом на передачу. Однако лучше здесь использовать традиционный способ.
При размещении всех компонентов программы в одном CGI-файле упрощается ее сопровождение. Цена — незначительное увеличение времени обработки при загрузке исходной страницы. Вот как все это выглядит:
#!/usr/local/bin/perlS -w
# программа ответа на форму о любимом сорте мороженого
# *и генерирования этой формы* (версия 3) use CGI qw(:standard);
my $favorite = param("flavor");
print header;
print start_html("Hello Ice Cream"), hi ("Hello Ice Cream");
if ($favorite) {
print p("Your favorite flavor is $favorite. ");
} else {
print hr, start_form;
print p ("Please select a flavor: ", textfield("flavor","mint"));
print end form, hr;
Если во время работы с броузером вы щелкнете на ссылке, которая указывает на эту программу (и если ссылка в конце URL не содержит ?whatever), то увидите экран, подобный изображенному на Рисунок 19.2. Текстовое поле изначально содержит значение по умолчанию, но это значение заменяется данными, введенными пользователями (если они есть).
Рисунок 19.2. Исходная заполняемая форма
Теперь заполните поле Please select a flavor, нажмите клавишу [Enter], и вы увидите то, что показано на Рисунок 19.3.
Рисунок 19.3. Результат обработки переданного с использованием формы запроса
В этой главе История создания
Глава 1
В этой главе:
История создания языка Perl
Назначение языка Perl
Доступность
Основные понятия
Прогулка по стране Perl
Упражнение
Скалярные данные" 1 Вот один из способов решения этой задачи
$pi = 3.141592654;
$result = 2 * $pi * 12.5;
print "radius 12,5 is circumference $result\n";
Сначала мы присваиваем константу (число к) скалярной переменной $pi. Затем мы вычисляем длину окружности, используя значение $pi в выражении, и, наконец, выводим результат, применяя строку, содержащую ссылку на него.
2. Вот один из способов решения этой задачи:
print "What is the radius: ";
chomp($radius = <STDIN>) ;
$pi = 3.141592654;
$result = 2 * $pi * $radius;
print "radius $radius is circumference $result\n";
Это похоже на предыдущий пример, но здесь мы попросили пользователя, выполняющего программу (применив для выдачи приглашения оператор print), ввести значение. Считывание строки с терминала осуществляется посредством операции <stdin>.
Если бы мы забыли применить функцию chomp, то получили бы посреди выведенной строки символ новой строки. Важно как можно быстрее выбросить этот символ из строки.
3. Вот один из способов решения этой задачи:
print "First number: "; chomp($a = <STDIN>) ;
print "Second number: "; chomp($b = <STDIN>) ;
$c = $a * $b; print "Answer is $c.\n";
Первая строка делает три вещи: приглашает вас ввести число, считывает строку со стандартного ввода, а затем избавляется от неизбежного символа новой строки. Поскольку мы используем значение $а строго как число, функцию chomp здесь можно опустить, потому что в числовом контексте 45\n — это 45. Однако столь небрежное программирование может впоследствии обернуться неприятностями (например, если нужно будет включить $а в сообщение).
Вторая строка делает то же самое со вторым числом и помещает его в скалярную переменную $Ь.
Третья строка перемножает эти два числа и выводит результат. Отметьте здесь наличие символа новой строки в конце строки (тогда как в первых двух строках он отсутствует). Первые два сообщения — это приглашения, в ответ на которые пользователь должен ввести число в той же строке. Последнее сообщение — это оператор; если бы мы выбросили символ новой строки, то сразу же за сообщением появилось бы приглашение shell. He очень-то хорошо.
4. Вот один из способов решения этой задачи:
print "String: "; $а = <STDIN>;
print "Number of times: "; chomp($b = <STDIN>) ;
$c = $a x $b; print "The result is:\n$c";
Как в предыдущем упражнении, первые две строки запрашивают значения двух переменных и принимают их. Однако здесь мы не выбрасываем символ новой строки, потому что он нам нужен! Третья строка получает введенные значения и выполняет над ними операцию многократного повторения строк, а затем выводит ответ. Обратите внимание на то, что за вычисляемой переменной $с в операторе print нет символа новой строки, поскольку мы считаем, что $с в любом случае заканчивается этим символом.
В этой главе Что такое
Глава 2
В этой главе:
Что такое скалярные данные
Скалярные операции
Скалярные переменные
Скалярные операции и функции
<STDIN> как скалярное значение
Упражнения
Изучаем Perl
Глава 3
В этой главе:
Список и массив
Литеральное представление
Переменные
Операции над массивами и функции обработки массивов
Скалярный и списочный контексты
<STDIN> как массив
Интерполяция массивов
Упражнения
Массивы и списочные данные" 1 Вот один из способов решения этой задачи
print "Enter the list of strings:\n";
@list = <STDIN>;
Sreverselist = reverse @list;
print @reverselist;
Первая строка приглашает ввести строки. Вторая строка считывает эти строки в переменную-массив. Третья строка формирует список с обратным порядком расположения элементов и заносит его в другую переменную. Последняя строка выводит результат.
Последние три строки можно объединить:
print "Enter the list of strings:\n";
print reverse <STDIN>;
Этот код работает аналогично предыдущему, так как операция print ожидает ввода списка, а операция reverse возвращает список. Далее операции reverse нужен список значений для реверсирования, а операция <stdin>, применяемая в списочном контексте, возвращает список строк — и они получают необходимое!
2. Вот один из способов решения этой задачи:
print "Enter the line number: "; chomp($a = <STDIN>) ;
print "Enter the lines, end with "D:\n"; @b = <STDIN>;
print "Answer: $b[$a-l]";
Первая строка приглашает ввести число, считывает его со стандартного ввода и удаляет назойливый символ новой строки. Вторая строка запрашивает список строк, а затем с помощью операции <stdin> в списочном контексте считывает все эти строки (до появления признака конца файла) в переменную-массив. Последний оператор выводит ответ, используя для выбора соответствующей строки ссылку на массив. Обратите внимание:
нам не нужно добавлять символ новой строки в конце, потому что строка, выбранная из массива @ь, уже заканчивается таким символом.
Если вы попробуете запустить эту программу с терминала, конфигурированного самым обычным образом, вам нужно будет нажать клавиши [Ctrl+D], чтобы обозначить конец файла.
3. Вот один из способов решения этой задачи:
srand;
print "List of strings: "; @b = <STDIN>;
print "Answer: $b[rand (@b)]";
Первая строка запускает генератор случайных чисел. Вторая строка считывает группу строк. Третья строка выбирает случайный элемент из этой группы и выводит его на экран.
Изучаем Perl
Глава 4
В этой главе:
Блоки операторов
Оператор if/unless
Оператор while/until
Оператор for
Оператор foreach
Упражнения
Управляющие структуры"
Глава 4 "Управляющие структуры"
1. Вот один из способов решения этой задачи:
print "What temperature is it? ";
chomp($temperature °° <STDIN>);
if ($temperature > 72) {
print "Too hot!\n";
} else (
print "Too cold!\n";
>
Первая строка приглашает ввести температуру. Вторая строка принимает введенное значение температуры. Оператор if в последних пяти строках выбирает для вывода одно из двух сообщений в зависимости от значения переменной $temperature.
2. Вот один из способов решения этой задачи:
print "What temperature is it? ";
chomp($temperature = <STDIN>) ;
if ($temperature > 75) (
print "Too hot!\n";
} elsif ($temperature < 68) (
print "Too cold!\n";
) else {
print "Just right!\n";
1
Здесь мы модифицировали программу, введя трехвариантный выбор. Сначала температура сравнивается со значением 75, затем со значением 68. Обратите внимание: при каждом запуске программы будет выполняться только один из трех вариантов.
3. Вот один из способов решения этой задачи:
print "Enter a number (999 to quit): ";
chomp($n = <STDIN>) ;
while ($n != 999) f
$sum += $n;
print "Enter another number (999 to quit): ";
chomp($n = <STDIN>);
1 print "the sum is $sum\n";
Первая строка приглашает ввести первое число. Вторая строка считывает это число с терминала. Цикл while продолжает выполняться до тех пор, пока число не станет равным 999.
Операция += накапливает числа в переменной $sum. Обратите внимание:
начальное значение этой переменной — undef, что очень хорошо для сумматора, потому что первое прибавляемое значение будет фактически прибавляться к нулю (помните, что при использовании в качестве числа undef равно нулю).
В этом цикле мы должны запрашивать и принимать еще одно число, чтобы проверка в начале цикла производилась по вновь введенному числу.
После выхода из цикла программа выводит накопленные результаты.
Если сразу же ввести 999, то значение переменной $sum будет равно не нулю, а пустой строке — т.е. значению undef в строковом контексте. Если вы хотите, чтобы программа в этом случае выводила нуль, нужно в начале программы инициализировать значение $s urn операцией $ sum = 0.
4. Вот один из способов решения этой задачи:
print "Enter some strings, end with "D:\n";
@strings = <STDIN>;
while (Ostrings) (
print pop @strings;
}
Сначала программа запрашивает строки. Эти строки сохраняются в переменной-массиве @strings (по одной на элемент).
Управляющее выражение цикла while — Sstrings. Это управляющее выражение ищет только одно значение ("истина" или "ложь"), поэтому вычисляет выражение в скалярном контексте. Имя массива (такое как @ strings) при использовании в скалярном контексте представляет собой количество элементов, находящихся в массиве в текущий момент. Поскольку массив не пуст, это число не равно нулю и, следовательно, имеет значение "истина". Эта идиома очень широко используется в Perl, она соответствует указанию "делать это, пока массив не пуст".
Тело цикла выводит значение, полученное путем "выталкивания" крайнего справа элемента массива. Следовательно, поскольку этот элемент выводится, при каждом выполнении цикла массив становится на один элемент короче.
Возможно, вам пришла в голову мысль использовать для решения данной задачи индексы. Действительно, эту задачу можно решить несколькими способами, однако в программах настоящих Perl-хакеров индексы встречаются редко, ибо почти всегда находится лучший метод.
5. Вот один из способов решения этой задачи без использования списка:
for ($number = 0; $number <= 32; $number++) {
$square = $number * $number;
printf "%5g %8g\n", $number, $square;
}
А вот как можно решить задачу с помощью списка:
foreach $number (0..32) (
$square = $number * $number;
printf "%5g %8g\n", $number, $square;
}
В обоих решениях применяются циклы с использованием операторов for и foreach. Тела этих циклов идентичны, потому что в обоих решениях значение переменной $ number при каждой итерации изменяется от 0 до 32.
В первом решении использован традиционный С-подобный оператор for. Первое выражение устанавливает переменную $number в 0, второе проверяет, меньше ли $number, чем 32, а третье инкрементирует $number при каждой итерации.
Во втором решении использован оператор foreach, подобный аналогичному оператору C-shell. С помощью конструктора списка создается список из 33 элементов (от 0 до 32). Затем переменной $number поочередно присваиваются значения, равные этим элементам.
Изучаем Perl
Глава 5
В этой главе:
Что такое хеш
Хеш-переменные
Литеральное представление хеша
Хеш-функции
Срезы хешей
Упражнения
Хеши" 1 Вот один из способов решения этой задачи
%map = qwfred apple green leaves blue ocean);
print "A string please: "; chomp($some_string = <STDIN>);
print "The value for $some_string is $map($some_string(\n";
Первая строка создает хеш из требуемых пар ключ-значение. Вторая строка выбирает строку, удаляя символ новой строки. Третья строка выводит на экран введенную строку и соответствующее ей значение.
Этот хеш можно создать и с помощью серии отдельных операций присваивания:
$map('red') = 'apple';
$map('green'( = 'leaves';
$map('blue'} = 'осеап',-
2. Вот один из способов решения этой задачи:
chomp(Swords = <STDIN>); # читать слова минус символы новой строки foreach $word (@words) (
$count{$word} = $count($word} + 1; # или $count{$word}++ t foreach $word (keys %count) {
print "$word was seen $count($word) times\n";
}
Первая строка считывает строки в массив @ words. Вспомните: в результате выполнения этой операции каждая строка становится отдельным элементом массива, причем символ новой строки останется нетронутым.
В следующих четырех строках осуществляется обход массива, при этом $word приравнивается по очереди каждой строке. Функция chomp отсекает символ новой строки, а потом начинается волшебство. Каждое слово используется как ключ хеша. Значение элемента, выбранного по этому ключу (слову), представляет собой значение счетчика повторений данного слова до текущего момента. Сначала в хеше элементов нет, поэтому если слово wild встречается в первой строке, то $count {"wild"} будет содержать undef. Это значение undef плюс единица оказывается равным нулю плюс единица, то есть единице. (Напомним, что при использовании в качестве числа undef означает нуль.) При следующем проходе у нас будет единица плюс единица, или два, и т.д.
Другой распространенный способ задания этой операции инкременти-рования приведен в комментарии. Опытные Perl-программисты обычно отличаются леностью (мы называем это "краткостью") и никогда не пишут одну и ту же ссылку на хеш в обеих частях операции присваивания, если можно обойтись автоинкрементированием.
После подсчета слов в последних нескольких строках программы осуществляется просмотр хеша и поочередное получение всех его ключей. После вычисления строкового значения сам ключ и соответствующее ему значение выводятся на экран.
Есть и другое решение, отличающееся от описанного только тем, что перед словом keys в третьей с конца строке вставлена операция sort. Без проведения операции сортировки выводимый результат кажется случайным и непредсказуемым. После сортировки все упорядочивается и становится предсказуемым. (Лично я редко использую операцию keys без сортировки; при наличии операции sort непосредственно перед keys повторные просмотры одних и тех же или похожих данных дают сопоставимые результаты.)
Изучаем Perl
Глава 6
В этой главе:
Ввод из STDIN
Ввод из операции "ромб"
Вывод в STDOUT
Упражнения