ЯЗЫК ПРОГРАММИРОВАНИЯ PERL В главе 11 вы изучили, как создавать скрипты CGI, ис- пользуя языки программирования C и C++. Однако наиболее широко применяемым языком для написания скриптов является Perl. Эта гла- ва посвящена языку Perl и его использованию. После того как вы научитесь программировать, используя Perl, вы сможете использо- вать его для написания скриптов, с помощью которых решаются раз- нообразные задачи программирования для Internet и Web. Особый упор будет сделан на тех особенностях, которые используются при написании CGI-скриптов. Если вы никогда не программировали ранее на языке Perl, используйте эту главу как отправную точку в его освоении. Концепции, с которыми вы познакомитесь в этой главе, научат, как писать профессиональные скрипты на языке Perl. В гла- ве рассматриваются не только основы программирования на Perl, но также и несколько других аспектов. К моменту окончания чтения главы вы будете в состоянии усвоить следующие ключевые концепции ? Perl является интерпретируемым языком программирования, спе- циально ориентированным на обработку текста. ? Программисты час- то называют программы на языке Perl скриптами. ? Используя Perl, программисты создают CGI-формы ? Perl поддерживает операции с файлами и с базами данных. Это делает его хорошо приспособленным для хранения и извлечения информации в соответствии с потребнос- тями пользователей Web. ? Perl снабжается отладочной программой, с помощью которой вы тестируете код Perl. PERL КАК ЯЗЫК ПРОГРАММИРОВАНИЯ Perl (Practical Extraction and Report Language ) является переносимым, интерпретируемым языком, идеально приспособленным для многочисленных приложений по обработке текста. Perl поддержи- вает структурированные программные конструкции, как и большин- ство языков программирования высокого уровня, и предлагает богат- ство встроенных возможностей, накопленных им за годы эволюции среде UNIX. Perl является бесплатным программным обеспечением. Его можно получить платно, и книга служит его бесплатному распространению). Фактически, Perl версии 5 имеется, на CD-ROM, прилагаемом к этой книге. Эта глава, однако, посвящена в первую очередь концепциям Perl версии 4, которая пол- ностью совместима с версией 5 и широко используется на Web. ИСТОРИЯ PERL Отцом языка Perl является Ларри Вол (Larry Wall). Он разра- ботан в 1986 году для создания отчетов о содержании многочислен- ных текстовых файлов в среде UNIX. Поскольку существующие сред- ства не подходили для решения такой задачи, Вол (Wall) изобрел новое средство для ее решения. Название Perl oзнaчает практичес- кий язык для извлечения и составления отчетов (Practical Extraction а Report Language). Вол продолжал добавлять различные возможности к Perl и сделал его доступным для общего пользования. Популярность Perl возрастает до сих пор, и он стал ' любленным средством многих программных пакетов. Умение программировать на Perl имеет возрастающую важность при составлении резюме. PERL - ИНТЕРПРЕТИРУЕМЫЙ ЯЗЫК ПРОГРАММИРОВАНИЯ Perl является интерпретируемым языком. Это означает, что программы, написанные на Perl, обычно исполняются путем вызова интерпретатора Perl и переда" ему списка команд, из которых сос- тоит программа. Поскольку интерпретатор тает и исполняет команды Perl именно таким образом, разработчики часто называют программы на Perl скриптами. Если вы вышли из мира UNIX-систем, то, вероят- но, знакомы со многими типам; скриптов, такими как скрипты shell, скрипты sed и т. д. В таком случае вы, вероятно , в состоянии оценить полезность и мощность языка, основанного на скриптах. Если вы пришли из мира DOS и Windows, то пакетные (.BAT)-файлы или программы на языке BASIC приходят на ум всякий раз, когда вы думаете об интерпретируемых скриптах. Если вы представляете себе файлы скриптов наподобие пакетных файлов MS-DOS, то вы, возможно, скептически относитесь к использованию скриптов, за исключением самых простейших задач. Однако если вы придерживаетесь непредвзя- того взгляда на вещи, то в скором времени сможете оценить всю мощь Perl. . СРАВНЕНИЕ PERL И ЯЗЫКОВ ПРОГРАММИОВАНИЯ С/С++ Структура Perl очень напоминает структуру языка программиро- вания С и на первый взгляд выглядит так же, как программа С. Все операторы С представлены в 1 Perl, а управляющие структуры, та- кие как if или for, имеются на языке Perl в несколько измененном виде. Чего не достает в Perl, так это указателей, структур и ти- пов, определяемых пользователем. Место языка С в программирова- нии неоспоримо, но не следует думать, что С-программа всегда луч- ше, чем эквивалентная программа на языке Perl. Как и у всякого средства, у Perl и у С есть свои области применения, к которым они лучше всего приспособлены. Надо хорошо знать оба языка, что- бы представлять, когда предпочтительнее использование одного из них. БОГАТСТВО ВОЗМОЖНОСТЕЙ ЯЗЫКА PERL Perl предоставляет разработчику широкий спектр возможностей для создания кратких и эффективных программ. Ниже приведены неко- торые наиболее замечательные черты Perl. Далее в главе вы позна- комитесь с использованием каждой из них: ? Ассоциативные массивы, которые индексируются программами с использованием нецелых клю- чей ? Автоматическое преобразование типов между целыми числами, числами с плавающей точкой и строками ? Автоматическое преобразо- вание размера массивов ? Функции для преобразования бинарных дан- ных ? Широкая поддержка так называемых регулярных выражений, ко- торые программы используют для поиска, замены и других операций, связанных с разбором текста ? Функции вывода/ввода файлов ? Фун- кции форматированного вывода, наподобие функции С, с добавлением к ним способности генерации отчетов на основе шаблонов (template) ? Полный набор.операторов С, с добавлением также операций по сравнению строк ? Функции для обработки списков, которые поддер- живают стеки, очереди и другие данные списочных типов ? Функции системного сервиса ? Богатый набор операторов и структур управле- ния, включая подпрограммы ИСПОЛЬЗОВАНИЕ PERL Чтобы разобраться, как использовать Perl, необходимо проана- лизировать коды написанные на нем. Самый простой путь познако- миться с языком Perl состоит в изучении коротких примеров. Сле- дующий раздел основан на коротких примерах для того, чтобы ввес- ти вас в курс дела. После того как вы поймете основы техники программирования на языке Perl, вы сможете писать на нем CGI- скрипты. ИСПОЛЬЗОВАНИЕ PERL КАК ФИЛЬТРА ДАННЫХ Средства UNIX-систем в значительной мере основаны на концеп- ции о том, что программа служит фильтром данных, поток которых поступает на вход, а отфильтрованные данные - на выход. Таким об- разом, программа-фильтр отбрасывает нежелательные данные. MS DOS также поддерживает концепцию фильтра данных. Утилита grep в сре- де UNIX представляет собой классический пример фильтра данных. Эта утилита сканирует входной поток данных в поиске строк, кото- рые соответствуют заданному шаблону. Программа направляет на вы- ход те строки, которые соответствуют этому шаблону. Она от- фильтровывает, отбрасывает строки, не удовлетворяющие шаблону. Perl идеально подходит для построения фильтров данных. Действи- тельно, вы можете создать простую версию утилиты grep, используя следующий короткий скрипт на языке Perl: $pattern = shift(@ARGV); # берет командную строку while (<>) { # читать строку из входного потока print if (/$pattern/); # output line if it matches } В этом случае скрипт просто просматривает входные данные строка за строкой. Если строка содержит текст, определенный пер- вым аргументом командной строки, то программа печатает такую строку. Не беспокойтесь, если написанный текст скрипта вам пока непонятен. В этой главе вы найдете описание всех операторов по- добного типа программ на языке Perl. ИСПОЛЬЗОВАНИЕ ЯЗЫКА PERL КАК ШЛЮЗА БЕЗОПАСНОСТИ Вопросам безопасности придается большое значение как в прог- раммировании CGI, так и при решении других задач, связанных с программным обеспечением для сетей. Часто бывает необходимо защи- тить файлы и другие ресурсы системы от угрозы со стороны пользо- вателей, которая может проистекать от их неаккуратности или даже злого умысла. Это особенно важно для Web-серверов, а также дру- гих серверов, таких как FTP-сервер, которые подключены к Internet, где наличие злоумышленных пользователей хорошо извес- тно. Одним из путей защиты системы от атак таких злоумышленников служит создание шлюзов безопасности, через которые пропускаются входные данные. В этом случае только данные, оцененные шлюзовой программой как безопасные, передаются в систему. Традиционно большая часть серверов Internet исполняется под системой UNIX и написана на языке С. Неверное использование программистами указа- телей на языке С ведет к нарушению безопасности работы системы. Одним из достоинств Perl, существенным при написании надежных шлюзовых программ, служит тот факт, что переменные строкового ти- па изменяют свою длину автоматически в зависимости от потребнос- ти. Строковые переменные содержат столько символов, сколько им присваивает скрипт. Perl не позволяет программе писать данные в одну переменную таким образом, чтобы нарушить целостность данных другой переменной. Имеется также специальная версия языка Perl, которую называют taintperl, в которой осуществляется проверка за- висимостей между данными и предотвращается выполнение системой команд по передаче данных серверу от источника, не заслуживающе- го доверия. Если испорченные или некорректные данные поступают на вход программы taintperl, то она помечает все значения командной строки, переменных окружения и входные данные как испорченные, предотвращая их дальнейшую передачу серверу и возникновение фа- тальной ошибки. FRONTEND-ПРОГРАММЫ ДЛЯ СВЯЗИ С БАЗОЙ ДАННЫХ Утилита типа frontend для базы данных представляет собой программу, которая упрощает доступ к серверу базы данных для ос- тальных программ. Такая программа обрабатывает запрос пользовате- ля к базе данных и на этой основе формирует свой запрос к базе данных с параметрами, необходимыми для доступа к данным на серве- ре. Frontend-программа может также обрабатывать результаты запро- са, формировать ответ и посылать его обратно пользователю. Как вы узнаете, программисты создают простые приложения для баз данных исключительно на языке Perl, причем не возникает необходимости в специальном сервере базы данных. Perl имеет встроенные возможнос- ти для отображения ассоциативных массивов (обсуждаемых дальше в этой главе) на файл базы данных. В результате доступ к файлу ба- зы данных в рамках скрипта Perl так же прост как и доступ к эле- ментам массива, поскольку ввод/вывод в файл является прозрачным для скрипта. Для более сложных приложений на основе баз данных Perl может выполнять роль связующего звена с сервером базы дан- ных и функционировать как Frontendпрограмма для базы данных. Нес- колько специальных версий языка Perl было создано для расширения поддержки конкретных серверов баз данных. Например, oraperl обес- печивает возможность доступа к серверам баз данных Oracle. ИСПОЛЬЗОВАНИЕ ЯЗЫКА PERL ДЛЯ НАПИСАНИЯ CGI- CКРИПТОВ. Как вы узнали из предыдущей главы, CGI обеспечивает узлам Web вoзмoжнoсть интерактивной работы с клиентскими программами, в качестве которых обычно выступает броузер. Во многих случаях уз- лы используют скрипты CGI для доступа к базам данных в тех слу- чаях, когда клиент и сервер должны обмениваться данными. Использование CGI позволяет пользователю получать доступ к базе данных на Web, используя обычный Web-броузер. CGI-скрипт читает и обрабатывает содержание НТМL-форм, устанавливает соединение с ба- зой данных, посылает ей запросы, обрабатывает результаты ответов, формируя на их основе новый НТМД документ, и затем посылает его обратно пользователю. Кроме того, все эти шаги должны быть сдела- ны так, чтобы обеспечить безопасность сервера. ЗНАКОМСТВО С ЯЗЫКОМ PERL Хочется верить, что вас удалось убедить в необходимости хо- тя бы рассмотреть использование языка Perl для написания скрип- тов CGI. В следующих разделах вы узнаете, как запускать Perl на исполнение и как создавать полезные скрипты на языке Perl. Благо- даря сходству Perl и С, в этой главе мы сосредоточим внимание на том, что объединяет их, и на их различиях. Больше внимания в гла- ве будет уделено различию между этими языками. НА ЯЗЫКЕ PERL Большинство учебников по языкам программирования начинается с простейшей программы, которая выводит текст . В соответствии с этой традицией мы приводим нашей книге несколько примеров программ . Следующий код служит для вывода на экран сообщения три раза, используя три различ- ных способа: # Три способа как сказать printf("Hello world\n"); printf("%s\n",'Hello world'); print "Hello World", "\n" Первая строка представляет собой комментарий. На языке Perl знак диез (#) означает комментарий. Когда Perl находит этот знак, он игнорирует весь текст, начиная с него и до конца строки. Знак диез служит единственным способом ввести комментарии на языке Perl. В отличие от С здесь нет конструкции, которая сразу бы оп- ределяла несколько строк комментариев. На первый взгляд функция printf выглядит так же, как в языке С. Однако вы можете заметить, что программа не содержит функции main. Хотя скрипты поддержи- вают подпрограммы (аналогичные функциям С), скрипт не определяет раздела, который бы содержал тело функции main. Вместо этого ин- терпретатор Perl сразу начинает исполнение скрипта с первого вы- ражения в файле. Второе выражение, содержащее функцию printf, опять-таки выглядит аналогично своему использованию в языке С, за исключением того, что вторая строка аргументов заключена в оди- нарные кавычки ('') в противоположность двойным (""), используе- мым в С. В языке Perl строка в двойных кавычках означает опреде- ленный род преобразования. Например, интерпретатор Perl преобра- зует выражение новой строки в двойных кавычках "\n" в символ но- вой строки. Скрипт Perl использует одинарные кавычки для включе- ния строковых литералов, т. е. строковых выражений, как это напи- сано выше. Например, Perl напечатает выражение в одинарных кавыч- ках ('\n') как два знака ('\') и 'n', а не как знак перехода на новую строку. Наконец, последняя строка кода программы содержит функцию print, которой нет в языке С. В этом случае наиболее по- лезная черта этой функции заключается в отсутствии скобок. Оказы- вается, что вы можете всегда включать скобки в состав функции языка Per]. Однако в большинстве случаев необходимости в них нет. Perl требует включения скобок только в том случае, если без них выражение оказывается не полностью определенным, двусмысленным. Тем не менее, включение скобок в код соответствует хорошей тради- ции, и вам не следует отказываться от нее. УСТАНОВКА PERL Теперь настало время попробовать работать с языком Perl не- посредственно. Если у вас не установлен Perl на вашей системе, то необходимо сделать это. Обратитесь к файлу Perl.txt на CD-ROM, который входит в комплект книги. Далее полагаем, что Perl пра- вильно установлен. Наберите команду для запуска скрипта Perl, аналогичную следующей: C:\PERL>perl script-name Например, создайте файл с именем hello.pl, содержащий пока- занную ниже строку: Print "Hello world\n" Далее в командной строке наберите следующую команду: C:\PERL>perl hello.pl На экране вы увидите следующий текст: Hello World Как уже говорилось, если вы используете UNIX-систему, то можно вызвать скрипт Perl таким же образом, как другую самостоя- тельную программу. Для того чтобы начать, отредактируйте файл так, чтобы первая строка была аналогична представленной ниже: #!/usr/bin/perl print "Hello world\n" В этом случае первая строка указывает системе, что необходи- мо запустить скрипт, используя Perl. Можно видеть, что эта стро- ка является комментарием и это не случайно, так что Perl, проиг- норирует ее. Тем не менее, большинство UNIX командных скриптов shell просмотрят два первых символа в любом исполняемом скрипте. Если первыми символами служат #!, то shell будет использовать ос- таток строки в качестве команды для запуска скрипта. В данном случае такой командой является /usr/bin/perl. Shell пересдаст имя скрипта Perl автоматически. Для того чтобы запустить скрипт, необходимо запустить команду chmod для того, чтобы указать скрип- ту на файл, который необходимо выполнить (например, chmod + х hello.pl). В зависимости от программы shell, также может потребо- ваться набрать команду rehash для того, чтобы указать программе shell, что вы добавили новую команду. Возможно, также потребует- ся модифицировать путь к Perl, если он не инсталлирован в подка- талоге /usr/bin вашей системы. Примечание: Большинство скриптов Perl используют в качестве рас- ширения.р1, но это необязательно. Если вы запускаете скрипт Perl как отдельную программу, то, возможно, более удобным будет вооб- ще опустить расширение. ИСПОЛЬЗОВАНИЕ ОТЛАДЧИКА PERL Может показаться преждевременным говорить сейчас об отладчи- ке Perl. Но использование отладчика может оказаться исключи- тельно полезным при изучении языка Perl. С ним вы можете легко испытать все программы, которые приведены в этой главе в качес- тве примеров. Фактически можно внести любое выражение Perl непос- редственно в отладчик, используя его в качестве интерактивного Perl. Таким способом можно ознакомиться со многими возможностями языка, что намного проще, чем создавать и запускать полные скрип- ты. Отладчик Perl встроен в сам Perl. Можно запустить отладчик, используя ключ -d в командной строке следующим образом: C:\PERL> Perl -d hello.pl В таком случае Perl загрузит скрипт hello.pl и начнет отлад- ку. Если вы используете UNIX-систему, то можете поместить коммен- тарий #!/usr/bin/perl -d в самом начале скрипта Perl. Если хоти- те загрузить Perl с отладчиком без загрузки скрипта, то можете использовать следующую команду: С: \> Perl -de 0 В таком случае аргумент командной строки -d указывает Perl на необходи- мость вызова отладчика, а аргумент -e 0 заставляет выполнить Perl скрипт, состоящий из 0 строк. Поскольку скрипт 0 не существует, то Perl просто запустит отладчик. Если Perl установлен на вашу систему корректно, то на экране вы увидите следующие данные, ко- торые говорят, что вы находитесь в отладчике: Loading DB routines from $RCSfile: perldb.pl,v $$Revision: 4.0.1.3 $$Date: 92/06/08 13:43:57 $ Emacs support available. Enter h for help. main '(p1000159:1): DB<1> Если Perl выводит ответ, но указывает на ошибку, такую как Can't locate perldb.pl @INC, то, значит, Perl установлен в вашей системе некорректно. В таком случае прочитайте readme-файлы, ко- торые сопровождают вашу версию Perl. В отладчике можно набрать любое выражение Perl, и он немедленно его исполнит. Дополни- тельно можно использовать следующие команды отладчика: ? h - рас- печатать в качестве подсказки список команд отладчика ? n - вы- полнять до следующего выражения ? - повторить последнюю ко- манду n или s ? p выражение - сокращение для команды print выра- жение ? q - окончить работу ? r - исполнять до выхода из подпрог- раммы ? s - один шаг по скрипту (со входом в подпрограмму) Например, следующая команда отладчика использует функцию print для того, чтобы вывести на экран сообщение Hello World: DB<1> prinf "Hello World\n"; Hello World DB<2> Используя отладчик с помощью команды р, можно вывести на эк- ран любое выражение. Для упрощения набора в отладчике можно опус- кать точку с запятой в конце выражения, поскольку отладчик доба- вит ее для вас. Наконец, отладчик всегда переходит на новую стро- ку для новой команды. Следующий код иллюстрирует использование команды р: DB<2> р "Hello World\n" Hello World DB<3> Как можно видеть, всякий раз, когда вы набираете команду от- ладчика, счетчик отладчика увеличивается на единицу, что находит отражение в его строке DB.Читая дальше эту главу, вам, вероятно, стоит запустить отладчик, чтобы иметь возможность набирать в нем примеры и работать с языком Perl интерактивно. Примечание: Для того, чтобы ввести выражение из многих строк в отладчик (debugger), необходимо использовать символ продолжения <\> конце каждой строки.. Иначе отладчик сообщит о синтаксичес- кой ошибке. Следующая команда иллюстрирует использование символа продол- жения при работе с отладчиком: DB<3> for ($i = 0; $i < 10; $i++) { \ cont: print $i; \ cont: } 0123456789 DB<4> В этом случае для вывода чисел от 0 до 9 использовался цикл for, который будет подробно рассмотрен в этой главе. ТИПЫ ДАННЫХ В PERL Типы данных используются в программах при объявлении пере- менных. Короче говоря, тип данных определяет то множество значе- ний, которые может принимать переменная, а также набор операций, которые программа может выполнять с ней. В языке Perl данные мо- гут быть числом или строкой символов. Одно значение называется скалярной величиной или просто скаляром. Ниже приведены примеры скалярных значений, которые используются в языке Perl: ? Десятич- ные: 127 или 127.0 или 1.27Е2 ? Шестнадцатиричные: Ox7F или 0x7f ? Восьмеричные: 0177 (первый 0 указывает, что используется восьмеричное число) ? Строка: "Hello World\n" или 'Hello World' Например, следующая команда использует отладчик Perl для того, чтобы вывести число 0177 восьмеричной системы, соответствующее числу 127 десятичной: DB<4> р 0177 127 Perl переводит данные в свой внутренний формат. Когда Perl печатает восьмеричные или шестнадцатиричные значения, он сначала переводит их в десятичный формат, как было показано. Примечание: Как вы узнаете, скрипт Perl позволяет использовать функцию printf для того, чтобы выводить, значения в вызываемом формате, в таком как восьмеричный или шестнадцатиричный. В качестве внутреннего представления всех чисел использует- ся формат с плавающей запятой двойной точности (double). Иными словами, среди внутренних форматов нет целочисленного. Тем не ме- нее, в большинстве случаев вы можете не обращать на это внимания, и Perl сделает все сам как надо. Например, если вы используете величины в контексте, где только целочисленные значения имеют смысл, Perl сам автоматически усечет число. Примечание: Если вы программируете на С и использовали целочис- ленное деление с усечением целых чисел автоматически, то, прог- раммируя на языке Perl, надо не забыть выполнить усечение вруч- ную, используя функцию int(). Следующая команда иллюстрирует, как Perl обрабатывает числа целого типа и с плавающей запятой: print 6 & 3; # выведет 2 print 6.9 & 3.1 # print 7 / 2 # выведет 2.3333 не целое print int(7/3) # выведет 2 Точно так же, как Perl преобразует числа с плавающей запя- той в целые числа: когда скрипт использует целочисленные значе- ния, он также преобразует числа в строки и наоборот, когда такое преобразование имеет смысл. Например, если скрипт использует чис- ла в контексте, где только строки имеют смысл, например, при сое- динении строк, он конвертирует числа в строки. Аналогичным обра- зом, если требуется использовать строки там, где только числа имеют смысл, то Perl конвертирует их в числа. Работая со скрипта- ми Perl, обычно не надо беспокоиться о внутреннем представлении скалярных величин. Perl поддерживает также концепцию булевых зна- чений, но не имеет для их описания специального типа. Как и в С, численное значение рассматривается истинным, если оно не равно нулю. Дополнительно строковое значение рассматривается как истин- ное, если оно не равно '' или '0'. Некоторые булевы операторы, такие как <>> (больше), возвращают единицу в качестве значения <истинно> и нуль - в качестве <ложно>. Тем самым, ваш скрипт дол- жен просто рассматривать ненулевые величины как строчного типа, так и числового в качестве булева значения <истинно>. Скрипты Perl могут группировать скалярные величины вместе и создавать список (list). Если скрипт хранит список в какой-то переменной, то эта переменная становится массивом (array). ПЕРЕМЕННЫЕ Perl поддерживает три типа переменных: скаляры, массивы и ассоциативные массивы. Как и в языке С, имена переменных пишутся с различением строчных и заглавных букв. Таким образом, имена VAR, Var и var описывают различные переменные. Скрипт может иметь скалярную переменную под именем var и переменную-массив, также названную var. Они будут различаться в языке Perl в соответствии с контекстом. Примечание: Переменные Perl нетипизированы, как это делается и в С. Например, скалярная переменная может содержать любой тип ска- ляра, и приведение типов осуществляется автоматически. Также, как вы могли уже заметить, переменные на языке Perl необязательно должны быть объявлены. Если переменная не объявлена, то Perl рас- сматривает ее как глобальную. Ниже вы познакомитесь с объявле- нием переменных и их областью видимости. СКАЛЯРНЫЕ ПЕРЕМЕННЫЕ Как отмечалось, скалярная переменная может содержать един- ственное значение. В языке Perl имена скалярных переменных всег- да начинаются со знака ($). В еле дующем выражении скалярной пе- ременной $age присваивается значение 35, а переменной $name - строковое значение . Затем используется функция print для вывода значения каждой из переменных: $age = 35; $name = 'Bob'; print ($name,'is',$age); Если вы сохраните эти выражения в файле под именем SCALAR.PL, то сможете запустить программу следующим образом: C:\PERL> Perl SCALAR.PL Bob is 35 МАССИВЫ Как было сказано выше, массивы представляют собой перемен- ные, принимающие в качестве значения список из скалярных величин. Следующий текст программы на языке Perl иллюстрирует объявление переменных типа массив и их инициализацию: @days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); print(@days); # выведет 'SunMonTueWedThuFriSat' print($days[4]); # выведет 'Thu' @weekdays = @days[1..5]; # значение ('Mon','Tue','Wed','Thu','Fri') @emptylist = (); # постой список Ссылка на переменные типа <массив> обычно начинается со зна- ка (@) и сопровождается значениями в квадратных скобках ([ ]). Как и в программировании на языке С, индексами массивов для скриптов всегда являются переменные целого типа, которые обычно начинаются с нулевого значения. Вы увидите исключения из этих двух правил в примерах, которые будут объясненены в этой главе. Третье выражение ($days[4]) служит примером массива, который ссы- лается на скалярное значение. Поскольку он содержит только один элемент, результирующее значение представляет собой скаляр. Если использовать знак ($) вместо знака (@), то скрипт будет ссы- латься на скалярную величину. Это замечание является очень важ- ным. Квадратные скобки указывают, что скрипт ссылается на массив. Знак $, в свою очередь, означает ссылку на скалярную величину. Инициализация массива @weekdays осуществляется путем выборки час- ти массива @days. В предыдущем примере массив @days использовал- ся без индекса. Когда индекс опущен, Perl ссылается на весь мас- сив. Аналогичным образом, в предыдущем примере массив @days ини- циализировался списком литералов. Кроме того, что массиву могут присваиваться в качестве значений литералы, скрипт может также присваивать массивам значения переменных или даже других масси- вов, как показано ниже: @stuff = ($age, $name) @FriendsOfMine = ('Joe','Mary', @FriendsOfYours); В следующем примере используются части массивов: @weekend = @days[0,6] ; # результат ('Sun','Sat') print (@days[1..5,0,6]); # выведет 'MonTueWedThuFriSunSat' Если скрипт использует переменную типа массив в контексте скаляра, то значением служит число элементов массива. Скалярным контекстом является такой контекст, где только скалярные значе- ния имеют смысл. Например, следующее выражение использует скаляр- ный контекст для массива stuff для того, чтобы определить число элементов содержащееся в массив. Если число элементов, больше или равно 2, то скрипт выдает сообщение и заканчивает исполнение: (@stuff >= 2) || die "Too much stuff! \n"; Функция die служит директивой языку Perl закончить выполне- ние и выдать при этом указанное сообщение. Если сообщение не со- держится, то функция просто заканчивает выполнение скрипта. Perl также поддерживает специальную конструкцию $# переменная, кото- рая возвращает последнее значение индекса в массиве. Например, следующее выражение for использует $[ для того, чтобы определить начальное значение индекса массива, и $# для определения послед- него из элементов массива. При этом с помощью выражения for выво- дятся значения каждого из элементов: for ($i =$[; $i <= $#stuff; $i++) { print $stuff[$i]; } Записанный цикл for можно заменить следующим эквивалентным выражением: Print @stuff; РОЛЬ КОНТЕКСТА АЛЯ ПЕРЕМЕННЫХ СКАЛЯРНОГО И ВЕКТОРНОГО ТИПА Отметим, что оператор построения списка (,) выглядит точно так же, как оператор (,) последовательного вычисления (sequential evaluation). Какой из операторов используется, зависит от контек- ста, в котором он появляется, в частности, является ли перемен- ная скаляром или массивом. Perl использует конструирование спис- ков в контексте массивов и последовательное вычисление для скаля- ров. Рассмотрим следующие выражения: @an_array = (1,2,3,4,5); $a_scalar = (1,2,3,4,5); В первом выражении инициализируется массив, в то время как второе выражение устанавливает значение скалярной переменной $a_scalar равным 5, отбрасывая первые четыре величины. Рассмот- рим два следующих выражения: print $assoc{1,2}; print @assoc{1,2}; В первом случае будет напечатано одно значение ассоциативно- го массива с двумя ключами, в то время как во втором будут напе- чатаны два значения ассоциативного массива с одним ключом. Из двух следующих выражений первое копирует список, тогда как вто- рое присваивает скалярной величине значение, равное размеру мас- сива: @x = @list; $x = @list; АССОЦИАТИВНЫЕ МАССИВЫ Ассоциативные массивы аналогичны обычным массивам в том от- ношении, что они представляют собой список скалярных переменных. Различие заключается в том, что массив должен использовать цело- численные значения в качестве индексов при выборе элементов мас- сива, тогда как ассоциативный массив может использовать величины любого типа для выбора элементов массива. Индексные величины для ассоциативного массива называются ключами. Рассмотрим следующие примеры: $ages{'Bob'} = 35; $ages{'Mary'} = 25; $, = ' '; # change output separator for print operator print @ages{'Bob','Mary'}; # выведет '25 35' print keys(%ages); # выведет 'Bob Mary' for $name (keys(%ages)) { print "$name is $ages{$keys}\n"; } Как можно видеть, программа присваивает значения переменной '$,' (скалярная переменная, именем которой является запятая). Скрипт использует это выражение для того, чтобы при дальнейшем использовании оператора print выходные данные не сливались между собой. Далее в этой главе обсуждаются специальные переменные, та- кие как '$,'. Ассоциативные массивы идентифицируются с помощью фигурных скобок. Так же как с массивами, при ссылках на ассоциа- тивный массив целиком индексы не используются. Например, ссылка @ages{'Bob', 'Mary'} использует индексы в скобках, что указывает на ассоциативный массив. Префикс @ указывает на то, что речь идет о массиве. Аналогичное использование знака доллара перед масси- вом указывает, что используется скалярная величина. Примечаиие: Если два ключа заданы, то вместе со знаком @ эта го- ворит о том, что речь идет о части ассоциативного массива и ре- зультат должен быть в виде списка. Такое выражение эквивалентно #ages{' Bob'}, #ages{'Mary'}. которое имеет своим значением вели- чину (35, 25). Выражение print keys(%ages) вызывает оператор keys, который возвращает полный список ключей ассоциативного массива. Ссылка %ages со знаком процента в качестве префикса означает, что ссыл- ка относится ко всему ассоциативному массиву. Обратите внимание, что цикл for ссылается на переменные, заключенные в двойные ка- вычки. Наконец, последний из рассмотренных примеров также ис- пользует оператор keys и вводит цикл for для распечатки всех со- четаний ассоциативного массива. Цикл for ссылается на переменные, заключенные в двойные кавычки. Perl, в свою оче редь, заменит значения, на которые ссылаются переменные, в то время, когда бу- дет анализировать строку. Программисты называют этот процесс под- становкой переменной или интерполяцией. Примечание: Perl не интерпретирует переменные, содержащие строки в одинарных кавычках. ОПЕРАТОРЫ PERL В то время как типы данных и переменных языка Perl значи- тельно отличаются от соответствующих типов языка С, операторы и выражения Per] должны вам показаться гораздо более знакомыми. Все операторы С присутствуют в языке Perl, за исключением операторы приведения типов (type), операторы обращения к содержимому указа- теля *ptr и оператора выбора члена структуры var.member или var->member. Кроме того, в языке Perl реализовано много новых операторов для использования в таких операциях как сравнение и обработка строк. АРИФМЕТИЧЕСКИЕ ОПЕРАТОРЫ Арифметические операторы действуют на числовые значения, и их результатом является число. Если выражение включает строковые операнды, то Perl конвертирует строковые значения в числовые пе- ред тем, как оценить выражение. Perl выполняет преобразование строк в числа подобно тому, как это делает функция atof()языка С в библиотеки времени выполнения. В настоящее время Perl поддержи- вает следующие арифметические операторы: ? + сложение ? - вычита- ние или изменение знака ? * умножение ? / деление (только для чи- сел с плавающей запятой) ? % взятие по модулю (только для цело- численных значений) Рассмотрим примеры следующих арифметических операций языка Perl: $x = 2.5; $y = 3; print ($x + 2*$y); # выведет 8.5 print (7 / $y); # выведет 2.3333333 print int (7 / $y); # выведет 2 print (7 % $y); # выведет 1 print (7.5 % $y); # выведет 1 Примечание: В языке Perl оператор деления всегда имеет результа- том 4ucw с плавающей точкой, а результатом взятия одного числа по модулю другого является целое число и причем предварительно оба операнда преобразуются к целому типу. Рассмотрим следующую операцию взятия по модулю: print (7.9 % 3.6); # выведет 1 то же (7 % 3) = 1 Perl также поддерживает операторы инкремента и декремента: ? ++ декремент в префиксной или постфиксной форме ? - инкремент в префиксной или постфиксной форме Рассмотрим примеры операций инкремента и декремента: $x = 4; ++$x; print $x; # выведет 5 $y = $x-; # уменьшит x после присвоения y значения x print "$y $x" # выведет 5 4 Наконец, Perl обеспечивает арифметический оператор для воз- ведения в степень (**). Рассмотрим следующие примеры использова- ния операции возведения в степень: $x = 2 ** 3; # результат 8 $x = 2 ** 0.5; # квадратный корень из 2 $x = -2 ** -3; # 1/(-2 в кубе), результат -1/8 (-0.125) ПОБИТОВЫЕ ОПЕРАТОРЫ Побитовые операторы воздействуют на бинарное представление целых чисел и имеют целочисленный результат. Если операндом яв- ляется строка или дробное число, Perl предварительно преобразует его в целое число, обрабатывает операнд, используя 32-битное представление. Все побитовые операторы С представлены в языке Perl: ? | побитовое ИЛИ ? & побитовое И ? ^ побитовое исключаю- щее ИЛИ ? ~ побитовая инверсия ? << сдвиг влево ? >> сдвиг вправо Рассмотрим следующие примеры побитовых операций: $x = 5; # 101 в двоичном $y = 3; # 011 в двоичном print $x | $y; # 7 (111) print $x & $y; # 1 (001) print $x ^ $y # 6 (110) print $x & ~1; # 4 (100) print $x << 2 # 20 (10100) print $x >> 1 # 2 (10) Так же как в С, поведение операторов сдвига вправо зависит от реализации язы ка в случае, если операнд является отрицательным. ОПЕРАТОРЫ СРАВНЕНИЯ Операторы сравнения сравнивают величины двух операндов. Так же как при работе с арифметическими операторами, Perl преобра- зует строчные операнды в численные перед тем, как выполнять срав- нение. Для того чтобы позволить скрипту сравнивать строки, кото- рые не являются числами, Perl имеет дополнительные операторы строкового сравнения. Эти операторы сравнивают строки, используя величины ASCII. Если численное значение задано как операнд при сравнении строк, оно сначала преобразуется в строку. Таблица 12.1 перечисляет операторы сравнения: Число Строка Значение = = eq равно != nе не равно > gt больше чем < it меньше чем >= gе больше или равно <= lе меньше или равно <=> cmp не равно (результат со знаком) Табл. 12.1. Операторы сравнения языка Perl Результатом операции сравнения является единица, если срав- нение истинно и нуль в противном случае. Однако последняя опера- ция (<=> или cmp) может возвращать значения -1, 0 или 1 в зависи- мости от того, является ли значение первого операнда меньше, чем второго, равным ему или большим. Примечание: Оператор cmp языка Perl ведет себя, аналогично фун- кции Strcmp() библиотеки времени выполнения языка С. Рассмотрим следующий пример сравнения: $x = 5; # x равно 5 print ($x < 4); # если false, то выведет 0 ЛОГИЧЕСКИЕ ОПЕРАТОРЫ Логические операторы анализируют булевы выражения и возвра- щают значения <истинно> или <ложно> в качестве результата. Perl обрабатывает операнды логических операций как булевы величины, т. е. как истинное или ложное значение. Логические операторы языка Perl включают следующие: ? || логическое ИЛИ ? && логическое И Perl всегда обрабатывает логические выражения слева направо. Кро- ме того. Perl всегда прекращает оценку, если уже выполненной оценки достаточно, чтобы определить значение результата. В допол- нение к общим логическим операторам Perl поддерживает следующие дополнительные логические операторы: ? ! логическое отрицание () ? ?: условная операция ? , последовательное выполнение Оператор логического отрицания (!) заменяет значение булевой ве- личины на противоположную. Так же как и в С, в языке Perl услов- ный оператор (?:) использует три операнда. Выражение, использую- щее условный оператор, имеет следующую форму: Condition ? true-result : false-result Аналогично, следующее выражение использует условный оператор для того, чтобы предоставить Бобу полный доступ, а всем остальным - ограниченный: $access = ($user eq 'Bob' ? 'Full' : 'Limited'); Оператор последовательного выполнения <,> (также известный как оператор запятая) не является вполне логическим оператором, пос- кольку он не анализирует истинность своих операндов. Perl выпол- няет операнды оператора последовательного выполнения слева напра- во и возвращает значение самого правого операнда. Следующий при- мер иллюстрирует использование оператора запятая в цикле for. For ($i=0, $j=10; $i<10; $i++, $j-) { print i$,' ',$j } СТРОКОВЫЕ ОПЕРАТОРЫ Поскольку Perl представляет собой язык для обработки текста, неудивительно, что в него включены дополнительные операторы для работы со строками. Ниже перечисляются операторы обработки строк: ?. конкатенация строк ? х репликация ? =~ сопоставление перемен- ной с образцом ? !~ то же, что и предыдущее, но с дополненным от- рицанием результата Первые два оператора легко иллюстрируются примером: print 'b' . 'an' x 2 . 'a'; # выведет 'banana' Как показано, это выражение использует конкатенацию строк и оператор репли-кации для того, чтобы напечатать строку . Два последних оператора используются для проверки того, включает ли строковый операнд заданный образец. Этот вопрос детально об- суждается в разделе <Регулярные выражения>. Следующий пример ил- люстрирует их использование: $var = 'banana'; print ($var =~ /ana/) ? TRUE : FALSE; В этом случае оператор проверки вхождения в строку образца (=~) использовался для проверки того, входит ли образец ana в пе- ременную $var. В данном случае выражение принимает значение <ис- тинно>. ОПЕРАТОРЫ ПРИСВАИВАНИЯ Если вы знакомы с языком программирования С, то формы опера- торов присваивания языка Perl должны быть для вас совершенно зна- комыми. Так же как и в С, эти операторы заставляют Perl выпол- нить специальные операции со значениями, которые появились с пра- вой стороны оператора, и затем выполнить присваивание: = += -= *= /= %= |= &= ^= ~= <<= >>= **= .= x= LVALUES В языке Perl, так же как и в С, lvalue представляет собой имя того, что стоит с левой стороны оператора присваивания. Та- ким образом, lvalue представляет собой целостность, которой мо- жет быть присвоено значение, например, lvalue может быть перемен- ной. Например, скрипт Perl не может присвоить значение строке символов, наподобие выражения = 32, поскольку не яв- ляется lvalue. Тем не менее, скрипт может присвоить значение пе- ременной $Bob, например, следующим образом $Bob = 32, поскольку переменная $Bob является lvalue. В языке Perl любая целостность, которая может использоваться как lvalue, обычно таковой и являет- ся. Например, следующее выражение упаковывает (pack) и распаковы- вает (unpack) список значений, причем список переменных в первом случае и три скалярных во втором являются lvalues: @color = ($r, $g, $b); # пакет цветов ($r, $g, $b) = @color; # распаковка цвета Когда вы работаете со списками в языке Perl, оператор прис- ваивания не обяза тельно относится ко всему списку. Скрипт может присваивать значения отдельным элементам списка, как показано ни- же: @items[2,4,7] = (100,200,300); В этом случае оператор присваивает значение трем элементам списка. Аналогичным образом следующее выражение распаковывает элементы списка, присваивая значения двух первых элементов двум скалярным переменным, а остаток массива - списочной переменной: ($arg1,$arg2,@rest) = @ARGV; # можно смешать скаляры и массивы ОПЕРАЦИИ ДЛЯ РАБОТЫ СО СПИСКАМИ В состав операций для работы со списками входят следующие: ? , конструктор списков ? .. оператор области ? х оператор репликации Вы уже использовали конструктор списков для инициализации массивов и создания списка переменных, использованных как lvalues. Оператор области возвращает в качестве значения последо- вательность целых чисел, которая начинается от левого операнда и продолжается до правого операнда включительно. Скрипты часто ис- пользуют оператор области совместно с конструктором списков для создания списков. Например, следующее выражение использует опера- тор области для того, чтобы создать список под именем @digits, который содержит числа от нуля до девяти: @digits = 0..9; # список (1,2,3,4,5,6,7,8,9) Аналогичным образом, это выражение может использовать опера- тор области для создания области изменений индексов массива. Предположим, что список @days содержит дни недели (начиная с вос- кресенья). В следующем выражении списку @weekdays присваиваются значения, начиная от понедельника до пятницы: @weekend = @days[1..5]; Наконец, следующее выражение использует два оператора облас- ти для создания списка шестнадцатиричных цифр: @hex_digits = (0..9,a..f); Оператор репликации просто создает копии данного операнда указанное число раз. Например, в следующем выражении список зна- чений 1, 2, 3 повторяется три раза: ОПЕРАТОРЫ ДЛЯ РАБОТЫ С ФАЙЛАМИ Perl содержит обширный список операторов для работы с файла- ми. Имеется не менее 27 операторов, возвращающих специфическую информацию о файле, даже не открывая его. Многие операторы языка Perl ориентированы на системы UNIX, но следующие операторы рабо- тают на любых системах: ? -d проверяет наличие каталога ? -е оп- ределяет наличие файла ? -s определяет размер файла ? -w опреде- ляет, можно ли писать в данный файл Следующие два файловых оператора возвращают булево значение. Третий оператор возвращает размер файла в байтах. Следующий текст иллюстрирует использование этих операторов: if (-e,'perl.exe') { print 'File size is:' -s 'perl.exe'; } else { print 'can\' t find perl.exe\n'; } (-w 'SomeFile') || die "Cannot write to SomeFile\n"; ПРИОРИТЕТЫ ВЫПОЛНЕНИЯ ОПЕРАТОРОВ Как и всякий язык программирования, Perl определяет приори- теты выполнения операторов, с помощью которых упорядочивается последовательность их выполнения. Таблица 12.2 перечисляет прио- ритеты операторов начиная от высшего и следуя к низшему: ? ++- ? ! ~ унарный минус ? ** ? =~ !~ ? * / % х ? +- ? <<>> ? -d -е -s -w (и другие файловые операторы) ? <> <= >= It gt le ge ? = = != < => eq ne cmp ? & ? |^ ? && ? || ? .. ? ? : = += -= *= Табл. 12.2. Приоритеты операторов языка Perl от высшего к низшему В своем скрипте вы можете изменять последовательность выпол- нения операторов с помощью скобок. КОНСТРУКЦИИ ЯЗЫКА PERL Perl поддерживает все выражения языка С, используя почти идентичный их формат. Например, управляющие конструкции if, while, do. for и goto используются в обоих языках в одинаковой форме. Как вы увидите в дальнейшем, оператор continue имеет нес- колько иное значение в языке Perl. Его прежнее значение теперь называют next, а оператор break называют теперь last. Perl не реализует оператор switch. Кроме того, некоторые выражения языка С можно найти в Perl в иных форматах и добавлены многие новые вы- ражения. ПРОСТЫЕ И СОСТАВНЫЕ ОПЕРАТОРЫ Простым выражением называется любая допустимая комбинация операторов и операндов. В языке Perl оператором является выраже- ние, заканчивающееся точкой с запятой. Как и в языке программиро- вания С, все операторы оканчиваются точкой с запятой. Когда вы вводите текст программы в отладчик, можно опускать точку с запя- той, поскольку отладчик поставит ее за вас. Следующий текст ил- люстрирует простой оператор присваивания на языке Perl: $Title = 'Web Programming'; Так же как и при программировании на С, скрипты Perl могут содержать блоки операторов, или составные операторы, которые по- мещаются в фигурные скобки ({}), как показано ниже: { # Операторы # Другой блок операторов } Ваши скрипты будут широко использовать блоки инструкций на- ряду с более сложными операторами. Как и в языке С, скрипты на языке Perl могут использовать блоки инструкций для определения области видимости (scope) локальных переменных. Однако определе- ние локальных переменных в блоке не является автоматическим. Для их декларации скрипт должен использовать ключевое слово local. Далее в этой главе мы рассмотрим область видимости переменных в деталях. УСЛОВНЫЕ ОПЕРАТОРЫ Многие предыдущие примеры использовали оператор if. В языке Perl оператор if почти что идентичен оператору if в языке С. Отличие, однако, состоит в том, что в языке С оператор if может использовать простую инструкцию без фигурных скобок, тогда как в языке Perl инструкции обязательно должны быть заключены в фигур- ные скобки, образуя блок. if (expr) statement; // приемлемо для C но не для Perl if (expr) { statement; # вот так нужно делать в Perl } Аналогичным образом инструкции языка Perl else работает нем- ного отлично от соответствующей инструкции в С. В языке Perl ин- струкции также должны быть заключены в фигурные скобки и образо- вать блок: // Пример в С неприемлемо в Perl if (expr1) statament1; else if (expr2) statement2; else ststement3; Ниже показано, что Perl позволяет использовать конструкцию elsif: if (expr1) { statament1; } elsif (expr2) { statement2; } else { ststement3; } ОПЕРАТОР UNLESS В языке программирования С программисты используют логичес- кое отрицание (!) для изменения булевой величины на противополож- ное, как показано ниже: if (!(expr)) // Отрицание на С { statement; } Наряду с использованием логического отрицания, скрипты Perl часто содержат оператор unless, который обеспечивает то же самое, что и записанный выше код на С. unless (expr) { statement; } Примечание: В отличие от языка С, Perl не содержит оператора пе- реключения switch. ОПЕРАТОР DO Одним из частных случаев блочных операторов служит оператор do, который позволяет блоку инструкций возвращать значения. Зна- чением, которое оператор do возвращает, является значение послед- него выражения, оцененного в рамках блока. Например, следующий оператор do сравнивает строковую переменную $Month с месяцами го- да и присваивает переменной $DayCount значение, равное числу дней в месяце: $DayCount = do { if ($Month eq 'September' || $Month eq 'April' || $Month eq 'June' || $Month eq 'November') { 30; } elsif ($Month eq 'Februry') { $Year & 3 ? 28 : 29; # Проверка на весокосный год } else { 31; } }; Обратите внимание, что Perl требует наличия точки с запятой в конце блока do. Не путайте блок do с оператором do while, кото- рый будет рассматриваться ниже в этой главе.