Глава 2. Скалярные переменные и списки
Коротко
В этой главе мы начинаем работать с данными. Perl особенно хорош по части обработки данных, и в этой книге вы найдете немало информации по данной теме. Сейчас мы попробуем разобраться, как Perl работает с двумя конкретными типами данных: скалярными переменными и списками.
Скалярные переменные
Скалярные переменные — это то, что в большинстве языков программирования называется простыми переменными (в Perl они также называются скалярами). Они хранят один элемент данных: число, текстовую строку или ссылку (о ссылках в Perl смотри главу 8). Их называют скалярами, чтобы отличать от конструкций, способных хранить несколько элементов (например, массивов).
Подсказка: В научных терминах скаляр — это простое числовое значение, в то время как векторы могут иметь несколько числовых компонент. Одномерные массивы в программировании часто называют векторами.
Имя скалярной переменной начинается с символа $. Это может показаться странным, но Perl использует именно этот способ. Тем самым ни одна из переменных не будет конфликтовать с зарезервированными ключевыми словами Perl, (то есть встроенными в язык идентификаторами). Значения скалярным переменным присваиваются с помощью оператора = — например
$scalar1 = 5;
$scalar2 = "Hello there!"
Списки
Как следует из названия, списки — это списки элементов данных. Эти элементы не обязательно являются скалярами, — они могут быть и массивами, и хеш-таблицами (оба эти типа данных будут рассмотрены в следующем разделе), а также собственно списками.
В отличие от скаляров или массивов, для списков не существует специального типа данных. Однако понятие списка в Perl очень важно, и мы будем использовать его на всем протяжении книги. Список — это синтаксическая конструкция, объединяющая разрозненные элементы данных. При определении списка элементы данных разделяются запятыми. Например, мы печатаем побуквенно слово Hello с помощью функции print, которая умеет обрабатывать аргументы, заданные в виде списка:
print "H", "e", "l", "l", "o";
Hello
Обратите внимание, что список "H", "e", "l", "l", "o" нельзя присвоить отдельной переменной, так как в Perl в явном виде переменных такого типа не существует <$FОднако вы можете создать ссылку на список, занести ее в обычную переменную и далее работать с содержимым ссылки (то есть списком) почти как с обычной переменной. Более подробно о ссылках речь пойдет в разделе 8. — Примеч. ред. >.
Встроенные функции Perl разделяются на две группы. Одни используют скалярные аргументы, а другие — списки (хотя на самом деле многие функции понимают и то, и другое). Откуда же Perl знает, когда интерпретировать данные как скаляр, а когда — как список? Он принимает решение, исходя из контекста. В Perl существует два основных контекста — скалярный и списочный. Имеется и более тонкая иерархия контекстов. Например, числовой и строковый контексты оба являются скалярными.
Таким образом, когда Perl ожидает встретить список (например, когда функция допускает в качестве аргумента только списки), данные интерпретируются как список. Если ожидается скалярное значение, данные интерпретируются как скаляр. На практике это означает, что необходимо заранее знать, какие функции являются скалярными, а какие — списочными. Я буду указывать, к какому типу относится функция, при первом упоминании о ней в этой книге, указывая тип ее аргументов. Например, определение для функции map будет иметь вид:
map блок список
В этом разделе скалярный и списочный контексты позднее будут рассмотрены более подробно. Введение закончено — перейдем к работе с программным кодом.
Непосредственные решения
Что такое скалярная переменная?
Скалярная переменная — это имя области памяти, в которой хранятся данные. Они могут быть числами, текстовыми строками или ссылками (ссылки работают подобно адресу другого элемента данных). Кроме этого, скалярная переменная может содержать и специальный тип данных Perl — так называемый неопределенный тип (см. раздел «Работа с неопределенными данными» далее в этой главе).
Обратите внимание, что скаляры могут хранить различные типы данных; иными словами, в Perl скаляры не имеют определенного типа (за исключением ссылок, для которых тип данных жестко проверяется). В этом отличие Perl от таких языков, как C. Perl определяет, какой тип данных находится в скалярной переменной (число, строка, и так далее), основываясь на контексте выполняемой операции.
Полезной особенностью Perl является то, что числа и строки в нем в некотором смысле неразличимы. Так, если подставить строку "123.45" там, где Perl ожидает увидеть число, то преобразование к числу 123.45 будет произведено автоматически. Аналогичным образом при необходимости число преобразуется в строку. (Это свойство позволяет применять нестандартные программные решения, некоторые из которых мы увидим ниже.)
Имена скалярных переменных
Имя, используемое для скалярной переменной, может содержать буквы, цифры и подчеркивания. Однако оно должно начинаться с символа $, что предотвращает конфликты с зарезервированными идентификаторами Perl. Имя переменной может быть длинным —до 255 символов, но эта характеристика зависит от платформы (то есть, некоторые реализации Perl допускают и более длинные имена, но имя с длиной не выше 255 будет правильно распознано любым вариантом Perl).
Поскольку имена скалярных переменных всегда начинаются с символа $ и тем самым не конфликтуют с зарезервированными идентификаторами, их можно записывать строчными буквами, как это делает большинство программистов. (Почти все служебные слова в Perl используют строчные буквы. Исключением являются дескрипторы файлов типа STDIN или функции, подобные блоку BEGIN для пакета.) Помните, что имена скалярных переменных чувствительны к регистру: имя $variable1 — это не то же самое, что имя $Variable1.
После начального символа $ в имени переменной может стоять буква или знак подчеркивания. На самом деле можно использовать и цифры, но тогда все имя должно состоять только из цифр. Можно даже использовать небуквенные символы, отличные от знака подчеркивания, — но в таком случае имя должно состоять (кроме начального $) ровно из одного символа — как, например, в случае специальных переменных Perl типа $!.
Подсказка 1: Заметьте, что хотя скалярные переменные и не могут конфликтовать с зарезервированными идентификаторами Perl из-за начального символа $, может возникнуть конфликт с именами для объектов, не требующими начального $ — например, дескрипторами файлов или метками. Чтобы избежать конфликта со служебными словами, для таких имен лучше использовать одну или несколько заглавных букв.
Подсказка 2: Переменные, имена которых состоят только из цифр, создаются самим Perl для специальных целей (см. раздел 6). Пользователь может читать значения этих переменных, но не может ничего им присваивать. Точно так же некоторые специальные переменные Perl доступны только для чтения, — присвоение нового значения вызовет ошибку.
Символ $, с которого начинается имя скалярной переменной, называется в Perl разыменовывающим префиксом (или, если использовать жаргон, funny character). Вот другие разыменовывающие префиксы, которые используются в Perl:
· $ — скалярные переменные
· % — хеши (они же — ассоциативные массивы, как это разъясняется в следующем разделе)
· @ — массивы
· & — подпрограммы
· * — запись таблицы символов — тип данных typeglob (более подробно об этом типе данных рассказывается в разделе 3.)
Присвоение скалярным переменным
Как в скалярную переменную заносятся данные? Для этого используется оператор присвоения. Например, вы можете поместить в переменную $variable1 значение 5:
$variable1 = 5;
Точно также выполняется присвоение текстовых строк:
$variable1 = "Hello there!";
Оператор присвоения может использоваться для присваивания данных любому объекту, стоящему слева от него (так называемое «левое значение» — lvalue). Если вы не знаете, что такое «левое значение», прочитайте следующий параграф.
Подобно остальным функциям Perl оператор присвоения возвращает некоторое значение. Значением оператора является данное, помещенное в соответствующую область памяти:
print $input = 123;
123
Что такое «левое значение»?
«Левое значение» — это элемент, слева от оператора присваивания и служащий «мишенью» для этой операции. Обычно «левое значение» представляет собой область памяти компьютера, в которую, указав ее имя, вы можете заносить данные. В качестве «левого значение» может выступать любая переменная. На самом деле в Perl эту роль иногда может играть и сама операция присваивания, как следует из примера:
chop($input = 123);
print $input;
12
Последний символ «отрезается» от переменной $input, а не от значения, возвращаемого операцией присвоения. Эта конструкция может часто встречаться, когда необходимо прочитать строку из входного потока, удалить символ конца строки и занести в переменную $input, — причем выполнить все это за один раз:
chop ($input = <>);
Использование чисел в скалярных переменных
Обратите внимание на следующую запись числового значения, которое позволяет сгруппировать цифры по разрядам для более легкого чтения результата:
$variable1 = 1_234_567;
Таблица 2.1. Числовые типы данных.
Тип |
Пример |
||
Значение с плавающей точкой |
1.23 |
||
Шестнадцатеричное значение |
0x123 |
||
Целое число |
123 |
||
Восьмеричное значение |
0123 |
||
Число в «научной» нотации |
1.23E4 |
||
Число с группировкой по разрядам |
1_234_5674 |
Работа с неопределенными данными: идентификатор undef
Кроме чисел, строк и ссылок, скалярные переменные могут содержать неопределенное значение, которое в Perl обозначается как undef (зарезервированное слово). Оно возвращается некоторыми функциями, и вы можете проверить его с помощью функции defined. Можно также присвоить переменной значение undef c помощью встроенной функции undef (см. ниже). Если подвергнуть непосредственной проверке значение undef, то оно интерпретируется как 0 (нулевое значение) в числовом контексте и как "" (пустая строка) — в строковом.
Рассмотрим пример. Пусть переменной $variable1 присвоено значение 5:
$variable1 = 5;
Затем с помощью функции undef эта переменная делается неопределенной:
$variable1 = 5;
undef $variable1;
Теперь проверим с помощью функции defined, является ли значение переменной неопределенным:
$variable1 = 5;
undef $variable1;
if (defined $variable1) {
print "\$variable1 is defined.\n";
} else {
print "\$variable1 is not defined.\n";
}
В результате код сообщит пользователю, что переменная является неопределенной:
$variable1 is not defined.
Описание констант
В Perl нет специальной синтаксической конструкции для числовых констант, но для нее можно создать заменитель самостоятельно (используя технику, обсуждаемую в главе 8 и в разделе главы 3, посвященному записям таблицы символов — специальному типу данных typeglob). Имя переменной, относящейся к этому типу, начинается с символа * (звездочка, или астериск). Чтобы создать константу, надо присвоить типу данных typeglob ссылку, как это делается в следующем примере (здесь константа хранит максимальное число файлов):
*MAXFILES = \100;
(Обратите внимание: имя составлено исключительно из заглавных букв, чтобы подчеркнуть, что это константа.)
Доступ к созданной константе осуществляется через имя $MAXFILES, как если бы это была обычная скалярная переменная:
*MAXFILES = \100;
print "$MAXFILES\n";
При попытке присвоить переменной $MAXFILES новое значение, вы получите сообщение об ошибке. Например, после выполнения кода
*MAXFILES = \100;
print "$MAXFILES\n";
$MAXFILES = 101;
на экран будет выведено
100
Modification of a read-only value attempted at constant.pl line 3.
Работа с логическими данными в Perl
Имеется еще один важный тип данных, о котором надо упомянуть: логические данные, или значения истина/ложь. Условные команды, управляющие выполнением кода (например, условные операторы if) используют логические проверки. Подобно языку С, любое непустое и ненулевое значение соответствует условию истина, нулевое или пустое — условию ложь. Соответственно, специального логического типа данных в Perl нет.
Тот факт, что любое ненулевое значение соответствует условию истина (напомним, что для Perl пустая строка — тот же ноль), весьма полезен для условных операторов. Например, благодаря этой особенности следующий цикл будет выполняться до самого конца входного потока, поскольку обращение к <> всегда что-то возвращает — даже если введена пустая строка (в этом случае возвращается символ `\n’):
while (<>) {
print;
}
Подсказка: В Perl в качестве значения ложь выступают следующие величины: а) числовые значения, равные нулю, б) пустая строка "", пустой массив () или пустой хеш {}, в) неопределенное значение undef, переменная с неопределенным значением, список неопределенных значений и/или переменных, г) дескриптор файла, не связанный с каким-либо файлом, е) пустые ссылки и незаполненные записи таблицы символов. Все остальные значения рассматриваются как истина.
Преобразование восьмеричных, десятичных и шестнадцатеричных чисел
В Perl восьмеричные числа задаются с ведущим нулем (например, 0123), а шестнадцатеричные — с префиксом 0x (например, 0x1AB). При работе числами, имеющими разные числовые основания, полезно знать, как преобразовывать их из одного формата в другой.
Преобразование шестнадцатеричного числа в десятичное
Для преобразования шестнадцатеричного формата в десятичный, используется функция hex:
print hex 0x1AB;
1063
Если для функции hex не задан аргумент, используется специальная переменная $_.
Преобразование десятичного числа в шестнадцатеричное
Чтобы преобразовать десятичное число в строку, являющуюся его шестнадцатеричным представлением, используйте функцию Perl sprintf с шаблоном %x:
print sprintf "%x", 16;
10
Преобразование восьмеричного числа в десятичное
Чтобы преобразовать восьмеричное число в десятичное, используется функция oct:
print oct 10;
8
Если для функции oct не задан аргумент, будет использована специальная переменная $_.
Преобразование десятичного числа в восьмеричное
Как и в случае шестнадцатеричных чисел, для преобразования десятичного числа в строку, являющуюся его восьмеричным представлением, используйте функцию Perl sprintf, но с шаблоном %o:
print sprintf "%o", 16;
20
Округление чисел
Чтобы округлить числовое значение до определенного числа десятичных знаков, используйте функцию sprintf с подходящим форматом. Например, чтобы округлить число до двух цифр после запятой, годится формат %.2f. Вот как этот метод работает при округлении числа «пи»:
print sprintf "%.2f", 3.14159265359;
3.14
То, что происходит именно округление, а не отбрасывание лишних разрядов, видно на следующем примере, где «пи» округляется до четырех цифр после запятой, и последняя цифра становится равной 6, а не 5:
print sprintf "%.4f", 3.14159265359;
3.1416
Однако приведенные примеры лишь показывают, как вывести округленные значения. Возможно, потребуется также округлять числовые значения и работать с ними как с обычными числами. Так как Perl обрабатывает данные исходя из контекста, то если уж в ваших силах интерпретировать текстовую строку как число, то и Perl это может (если текстовая строка действительно описывает число). В следующем примере мы округляем число и запоминаем строку в переменной $variable1:
$variable1 = sprintf "%.4f", 3.14159265359;
Теперь можно использовать значение, находящееся в переменной $variable1, как число, выполнив над ним арифметическую операцию, — например, прибавив к нему значение 0.01:
$variable1 = sprintf "%.2f", 3.14159265359;
$variable1 += .01;
Теперь проверим результат:
$variable1 = sprintf "%.2f", 3.14159265359;
$variable1 += .01;
print $variable1;
3.15
Использование строк в скалярных переменных
В скалярных переменных можно хранить как числа, так и строки:
$variable1 = "Hello!";
Надо отметить, что для конкатенации (объединения) двух строк в Perl нельзя использовать операцию сложения, как это принято в других языках. Например, следующие команды
$variable1 = "Hello ";
$variable2 = "there\n";
print $variable1 + $variable2;
дадут только сообщение об ошибке и ноль в качестве результата:
Argument "there\n" isn’t numeric in add at - line 3
Argument "Hello " isn’t numeric in add at - line 3
0
Причину легко понять: в данном случае Perl пытается интерпретировать текст исходя из числового контекста (операция сложения).
Вместо этого следует использовать оператор конкатенации Perl, в роли которого выступает точка (.):
$variable1 = "Hello ";
$variable2 = "there\n";
print $variable1 . $variable2;
Hello there
Строки могут задаваться с помощью одинарных или двойных кавычек:
$variable1 = "Hello.";
$variable2 = 'Hello again.';
Между этими способами есть тонкое различие. Perl вычисляет переменные и некоторые выражения в теле строки, когда она ограничена двойными кавычками (более подробно об этом рассказано в следующем разделе). Если строка ограничена одинарными кавычками (апострофами), то Perl рассматривает ее как константу без попыток интерпретировать тело строки.
В строках, ограниченных двойными кавычками, можно использовать escape-последовательности, управляющие их форматированием и позволяющие задавать символы, которые иначе записать не удастся (см. таблицу 2.2). Например, чтобы внести в текст двойную кавычку, можно использовать последовательность \":
print "I said, \"Hello\".";
I said, "Hello".
В строках, ограниченных одинарными кавычками, escape-последовательности не работают.
Таблица 2.2. Escape-последовательности и их значение.
Символ |
Значение |
||
\’ |
одинарная кавычка, или апостроф (‘) |
||
\` |
обратный апостроф (`) |
||
\" |
двойная кавычка (") |
||
\\ |
обратная косая черта (\) |
||
\$ |
символ доллара ($) |
||
\@ |
символ at-коммерческое (@) |
||
\t |
символ табуляции (TAB, HT) |
||
\v |
символ вертикальной табуляции (VT) |
||
\n |
символ новой строки (LF) |
||
\e |
символ escape (ESC) |
||
\u |
сделать следующую литеру заглавной |
||
\l |
сделать следующую литеру строчной |
||
\U |
сделать следующую группу литер (до команды \E) заглавными |
||
\L |
сделать следующую группу литер (до команды \E) строчными |
||
\Q |
в следующей группе литер (до команды \E) считать, что ко всем небуквенным литерам добавлена обратная косая черта, — это заставляет Perl интерпретировать их как обычные символы |
||
\E |
завершает команды \L, \U и \Q |
||
\r |
символ возврата каретки (CR) |
||
\f |
символ прогона страницы (FF) |
||
\b |
символ забоя (BS) |
||
\a |
символ звукового сигнала (BEL) |
||
\033 |
восьмеричный символ |
||
\x1b |
шестнадцатеричный символ |
||
\c[ |
управляющий символ (control character) |
Символ новой строки в текстовых строках
Во всех операционных системах сценарии Perl используют символ \n, чтобы обозначить конец строки. На самом деле такой вещи, как неизменный и физически существующий в конце строки текста символ \n, не существует. Это — лишь иллюзия, которую договорились поддерживать библиотеки языка С и интерпретатор Perl. Так, например, после команды print "\n"; Perl для Unix выведет в выходной файл двоичный символ 0x0D, а Perl для Windows — пару символов 0x0A и 0x0D. (Аналогичное преобразование конца строки происходит при вводе, так что с точки зрения пользователя в 99% случаев это расхождение между интерпретаторами Perl не будет заметно.)
То есть, далеко не все системы воспринимают \r как двоичный символ CR, и \n как двоичный символ LF в кодировке ASCII. Например, для компьютеров Macintosh эти символы переставлены местами. На некоторых системах, не использующих символ конца строки, печать \n или \r может привести к потере выводимых данных. Поэтому используйте символ \n, когда вы имеете в виду конец строки в рамках вашей операционной системы, но меняйте его на явный символ, когда вам требуется истинное двоичное значение.
(Например, большинство сетевых протоколов ожидают (и предпочитают) в качестве символа конца строки комбинации CR+LF (\012\015 или \cJ\cM), и хотя они, скорее всего, поймут в этом качестве символ LF, они вряд ли обработают как конец строки одиночный CR. Поэтому если вы привыкнете использовать в сетевых приложениях символ \n, вы рано или поздно столкнетесь с неприятностями.)
Подстановка переменных (интерполяция строк)
Когда вы используете в строке, заключенной в двойные кавычки, имена переменных, Perl подставляет вместо них значения, присвоенные переменным. Например, если у вас есть переменная $text, в которой хранится слово Hello
$text = "Hello";
то вы можете использовать ее имя в теле строки, и Perl подставит Hello вместо имени переменной:
$text = "Hello";
print "Perl says: $text!\n";
Perl says: Hello!.
Этот процесс называется подстановкой, или интерполяцией (interpolation). В частности, в нашем примере Perl интерполировал значение, содержащееся в переменной $text, в тело строки, заключенной в двойные кавычки.
Однако если заключить тело строки в одинарные кавычки (апострофы), то Perl не будет выполнять интерполяцию:
$text = "Hello";
print ’Perl says: $text!\n’;
Perl says: $text!\n.
То есть, одинарные кавычки используются, когда не требуется вычислять выражение.
А что, если вы хотите интерполировать переменную как часть другого, а не отдельно взятого слова? Например, что если переменная $text содержит префикс «un», и нужно добавить его к слову «happy»? Очевидно, что использовать выражение типа $texthappy не получится, так как Perl будет искать переменную с этим именем, а не интерполировать $text с целью породить слово «unhappy». Вместо этого следует использовать фигурные скобки { и }, позволяющие отделить имя переменной, которую вы хотите интерполировать как часть полного слова:
$text = "un";
print "Don’t be ${text}happy.";
Don’t be unhappy.
Программисты часто используют интерполяцию для конкатенации строк:
$a = "Hello";
$b = "there";
print "$a $b\n";
Hello there
Прежде чем перейти к следующему разделу, я покажу еще один трюк. Если вы используете в качестве ограничителя строки обратный апостроф (`), то ее содержимое интерпретируется как команда, передаваемая операционной системе, а результат выполнения команды (то есть текст, выведенный на экран) заносится в переменную в качестве значения. Например, в Unix вы можете таким образом выполнить команду uptime, которая сообщает, сколько времени прошло с момента последней загрузки компьютера:
$uptime = `uptime`;
print $uptime
4:29pm up 18 days, 21:22, 13 users, load average: 0.30, 0.39, 0.42
Точно так же этот прием работает и в операционной системе MS DOS, где команду dir можно выполнить следующим образом:
$dirlist = `dir`;
print $dirlist;
Directory of C:\perlbook\temp
. <DIR> 10-07-99 4:02p .
.. <DIR> 10-07-99 4:02p ..
TEMP PL 3,535 10-07-99 4:06p T.PL
Подсказка: Встроенные документы (см. раздел «Вывод неформатированного текста: встроенные документы» предыдущей главы) в смысле интерполяции эквивалентны строкам, заключенным в двойные кавычки.
Сложные случаи интерполяции
Вы можете объединить результат работы подпрограммы с другими строками с помощью оператора конкатенации:
$string = $text1 . mysubroutine($data) . $text2;
С другой стороны, планирование с опережением позволяет (с помощью конструкции ${...}) напрямую интерполировать внутрь заключенной в двойные кавычки строки значение, возвращаемое подпрограммой (о подпрограммах речь пойдет в главе 7). Например, вы хотите интерполировать внутрь строк значение, возвращаемое подпрограммой getmessage. Формально это можно проделать следующим образом (обратите внимание, что требуется в явном виде использовать разыменовывающий префикс & — первый и обычно необязательный символ в имени подпрограммы):
print "${&getmessage}";
Однако, что на самом деле делается этой командой, так это подстановка строки, возвращаемой подпрограммой при ее вызове, а затем интерпретация результата как имени переменной, значение которой надо подставить. Трюк в том, чтобы задать в подпрограмме нужное значение для этой переменной и вернуть имя переменной:
print "${&getmessage}";
sub getmessage {
$msg = "Hello!";
return "msg"
};
Теперь команда print "${&getmessage}" выполнит то, что мы хотим:
print "${&getmessage}";
sub getmessage {
$msg = "Hello!";
return "msg"
};
Hello!
Однако такой прием сработает лишь для написанных вами подпрограмм. Имеется способ, работающий в более широком спектре вариантов, который заставляет Perl вычислить значение подпрограммы и подставить его внутрь строки ( он использует синтаксические конструкции, которые станут понятны лишь после прочтения главы 8). Вот как выглядит искомая синтаксическая конструкция:
$string = "text ${\(scalarfunction data)} text";
Если же вы используете функцию, возвращающую список значений, то вам поможет конструкция под названием безымянный, или анонимный массив (anonymous array):
$string = "text @{[listfunction data]} text";
Например, если вы хотите использовать функцию Perl uc для того, чтобы вводимая следом за ней буква стала строчной (и забыли, что это легко реализуется с помощью escape-последовательности \u), это можно сделать следующим образом:
print "${\(uc \"x\")}";
X
Обратите внимание: внутренние двойные кавычки, использованные для аргумента функции, заданы с помощью escape-последовательности \" — в противном случае у Perl были бы проблемы при синтаксическом разборе строки, как единого целого.
Обработка кавычек и слов без кавычек
В Perl кавычки, окружающие одиночное слово, иногда оказываются лишними. Так происходит в случае, когда слово может быть интерпретировано однозначно. Например, в случае, рассмотренном ниже присвоение строки переменной $text очевидно, поэтому кавычки не требуются:
$text = Hello;
Так что если теперь вывести переменную $text, то получим, что и следовало ожидать:
$text = Hello;
print $text;
Hello
Такие слова без кавычек называются в Perl одиночными словами, или простыми словами (barewords). Однако если используется более одного слова, то это уже не «простое слово», и подобная конструкция работать не будет:
$text = Hello there; # Not good
print $text; # Does not work
Иногда простые слова могут путаться с метками или дескрипторами файлов (ни то, ни другое не требует разыменовывающего префикса). Вы можете сделать Perl менее терпимым к одиночным словам и заставить интерпретатор печатать предупреждающее сообщение всякий раз, когда слово без кавычек не может быть проинтерпретировано как имя подпрограммы:
use list ’subs’;
Кроме того, что можно опускать лишние кавычки, специальные синтаксические конструкции из таблицы 2.3 помогут также добавть кавычки средствами самого Perl.
Таблица 2.3. Синтаксические конструкции для кавычек.
Синтаксис |
Результат |
Интерполирует? |
Объект |
||
q/.../ |
'...' |
Нет |
Строка |
||
qq/.../ |
"..." |
Да |
Строка |
||
qx/.../ |
`...` |
Да |
Команда |
||
qw/.../ |
(...) |
Нет |
Список слов |
||
/.../ |
m/.../ |
Да |
Шаблон поиска |
||
s/../../ |
s/../../ |
Да |
Подстановка (substitute) |
||
y/../../ |
tr/../../ |
Нет |
Замены (translate) |
Например, если вам хочется напечатать строку «I said, "Hello."», то это можно, конечно, сделать с помощью escape-последовательностей:
print "I said, \"Hello.\"";
I said, "Hello."
Но лучше от такого количества escape-последовательностей (на жаргоне Perl-программистов это называется LTS — «ученический синдром зубочистки» (learning toothstick syndrome): начинающие имеют склонность использовать излишне много символов обратной косой черты, то есть «зубочисток»). Чтобы позаботиться о двойных кавычках внутри строки, можно использовать конструкцию q//:
print qq/I said, "Hello."/;
I said, "Hello."
На самом деле использование наклонной черты не обязательно. Допустим почти любой небуквенный символ, отмечающий начало и конец строки:
print qq|I said, "Hello."|;
I said, "Hello."
Можно даже использовать символы, которые в других случаях играют в Perl специальную роль — например, символ комментария (здесь наглядно видно, что в Perl любые конструкции зависят от контекста):
print qq#I said, "Hello."#;
I said, "Hello."
Можно также использовать для этой цели скобки:
print qq(I said, "Hello.");
I said, "Hello."
В данном случае скобки служат для ограничения конструкции qq, а не для группировки параметров при обращении к подпрограмме. (Кстати, о подпрограммах. В Perl, где почти всегда есть несколько способов для достижения какого-либо результата, разрешается еще и опускать скобки при вызове подпрограммы, если это не вызывает путаницы с остальными членами выражения.)
Наконец, необходимо отметить, что ограничиваться круглыми скобками тоже нет необходимости: можно использовать любые скобки — круглые, фигурные, квадратные или даже угловые:
print qq{I said, "Hello."};
I said, "Hello."
print qq[I said, "Hello."];
I said, "Hello."
print qq<I said, "Hello.">;
I said, "Hello."
Что такое список?
Perl позволяет собирать скалярные переменные (и другие типы данных — массивы, хеш-таблицы) в списки. Списки очень важны для Perl. Встроенные функции Perl разбиты на две группы: для работы со скалярами, и для работы со списками (на самом деле некоторые работают и с тем, и с другим.)
В Perl нет специального типа данных для списков. Однако имеется оператор списка, — а именно, пара круглых скобок. Чтобы создать список, достаточно перечислить через запятую его элементы и заключить всю конструкцию в круглые скобки. Например, выражение (1, 2, 3) соответствует списку, состоящему из трех элементов: 1, 2 и 3.
Подсказка: Элементами списка могут быть только скалярные значения. Вы, конечно, можете использовать конструкцию вида (1, 2, (4, 5), 7, 8), но это то же самое, что и (1, 2, 4, 5, 7, 8) — индивидуальность внутреннего списка теряется, а его элементы просто вливаются во внешний список.
Оператор print является «списочным» <$FКак и в С, в Perl нет различия между функциями и процедурами (командами). Однако во многих случаях нет различия и между функциями и операторами — так, ключевое слово «print» играет роль оператора, когда его аргументы указаны без скобок, и роль функции, когда его аргументы заключены в круглые скобки (подробнее см. раздел 4) — Прим. перев.>. Если вы подадите ему на вход список, он объединит его элементы в одну строку (выполнит конкатенацию отдельных строк). Например, если задать на входе список (1, 2, 3)
print (1, 2, 3);
то на выходе мы увидим
123
Как и раньше, круглые скобки вокруг списка можно опустить — в этом случае Perl будет интерпретировать print как команду, а не как вызов функции:
print 1, 2, 3;
123
Ссылка на элементы списка через индекс
После создания списка вы можете ссылаться на его отдельные элементы, используя квадратные скобки []. Можно считать, что это оператор индекса списка. Например, если сделать список, состоящий из литер a, b и c (их нет необходимости заключать в кавычки, поскольку это — простые слова), то можно сослаться на элемент с индексом 1 (буква b — в Perl элементы нумеруются с нуля). Например,
$variable1 = (a, b, c)[1];
Если распечатать эту переменную, то получим ожидаемый результат:
$variable1 = (a, b, c)[1];
print $variable1;
b
Обратите внимание, что можно индексировать даже список, возвращаемый функцией. Таким образом, мы получаем простой способ работы со списковыми функциями, когда на выходе требуется только скаларный результат из полного списка значений.
Присваивание списков спискам
Можно присвоить один список другому, используя оператор присвоения =. Например, здесь мы присваиваем элементам списка ($a, $b) соответствующие им элементы списка ($c, $d):
($a, $b) = ($c, $d);
Элементы списка, стоящие справа, рассматриваются как вычисляемые выражения, а элементы списка слева — как «левые значения» оператора присваивания. Тем самым два списка могут содержать пересекающиеся переменные, и при этом не возникнет путаница — список в правой части, вычисляется до операции присваивания. Например, таким способом можно поменять местами значения переменных $a и $b, не прибегая к помощи промежуточной переменной:
($a, $b) = ($b, $a);
Списки, участвующие в этой операции, могут быть разной длины. В следующем примере переменным $a и $b присваиваются первые два элемента списка, состоящего из трех элементов:
($a, $b) = (1, 2, 3);
print $a;
1
print $b;
2
Если число элементов в левой части окажется больше числа элементов в правой, оставшиеся переменные получат неопределенное значение undef. Это произойдет даже в том случае, если до операции присвоения у них уже было некоторое значение:
$a = 0; $b = 0; $c = 0;
($a, $b, $c) = (1, 2);
print $a, "\n";
print $b, "\n";
print $c, "\n";
1
2
Use an uninitialized value at - line 5
Если в качестве «левых значений» задать undef, то соответствующие элементы списка справа, будут пропущены:
($a, undef, $b) = (1, 2, 3);
print $a;
1
print $b;
3
Преобразование списка
Чтобы выполнить одну и ту же операцию над всеми элементами списка, используется функция map:
map блок список
map выражение список
Она выполняет код, указанный как блок операторов или как выражение, для каждого элемента списка. Перед выполнением очередной операции специальной переменной $_ присваивается соответствующий элемент списка. На выходе получаем результат вычислений. Например, чтобы преобразовать все элементы списка к строчным буквам, можно использовать встроенные функции Perl lc (которая заменяет в строке заглавные буквы на строчные) и map:
($a, $b) = map (lc, A, B);
print $a, $b;
ab
(Здесь использовано то свойство, что функция lc использует переменную $_ в качестве входного значения, если ей не указать параметры.)
Объединение элементов списка в строку
Для конкатенации всех элементов списка в одну строку, можно использовать функцию join:
join выражение, список
Эта функция объединяет в одну строку элементы списка (напомним, что в Perl арифметические и строковые данные свободно преобразуются друг в друга), используя заданное выражение в качестве разделителя между элементами. Вот пример ее работы:
print join (":", "12", "00", "00");
12:00:00
Строго говоря, можно было бы обойтись и без двойных кавычек, но если убрать двойные кавычки вокруг "00", то Perl будет интерпретировать этот элемент как число ноль, и в результате мы потеряем ведущие нули, получив на выходе 12:0:0.
В случае «чистой» конкатенации без разделителей достаточно задать в качестве выражения пустую строку:
print join ("", H, e, l, l, o);
Hello
Превращение строки в список
Чтобы разбить строку на части и превратить ее в список, можно использовать встроенную функцию а split:
split /шаблон/, выражение, верхний-предел
split /шаблон/, выражение
split /шаблон/
split
Функция split разбивает строковое выражение по границам, отмеченным подстрокой-шаблоном, и образует из частей список (при этом сам шаблон удаляется). Если задан верхний предел, который должен быть положительным числом, число элементов списка не будет превышать заданное. Если выражение не задано, используется специальная переменная $_. Если отсутствует шаблон, происходит разбивка по так называемым «пробельным символам» (сюда входит пробел, знак табуляции, символ новой строки, и так далее, причем несколько «пробельных символов» подряд рассматриваются как один).
Следующий пример превращает строку "H,e,l,l,o" в список из отдельных букв и выводит его на печать:
print split /,/, "H,e,l,l,o";
Hello
Сортировка списков
Для сортировки списков используется функция sort:
sort подпрограмма список
sort блок список
sort список
Эта функция сортирует список и возвращает отсортированный результат. Пользователь может задать правило сортировки в виде имени подпрограммы или в виде блока операторов. Подпрограмма должна возвращать результат сравнения двух параметров аналогично операторам сравнения <=> и cmp (см. главу 4). Подпрограмма может быть заменена блоком операторов, выполняющих ту же функцию. Если не указаны ни имя подпрограммы, ни блок операторов, функция sort использует стандартную операцию сравнения строк. Например, давайте отсортируем список ("c", "b", "a"):
print sort ("c", "b", "a");
abc
Можно явно задать блок, сравнивающий две строки, и получить тот же результат:
print sort {$a cmp $b} ("c", "b", "a");
abc
Можно сортировать список в обратном порядке:
print sort {$b cmp $a} ("c", "b", "a");
cba
Можно использовать числовое сравнение для сортировки значений:
print sort {$a <=> $b} (3, 2, 1);
123
Наконец, тот же код можно поместить в подпрограмму:
sub myfunction {
return (shift(@_) <=> shift(@_));
}
print sort myfunction (3, 2, 1);
123
что эквивалентно блоку
print sort {myfunction($a, $b)} (3, 2, 1);
123
Инвертирование списка
Чтобы инвертировать список, используйте функцию reverse:
reverse список
Вот как можно использовать эту функцию, чтобы инвертировать элементы в списке (1, 2, 3):
print reverse (1, 2, 3);
321
Выбор элементов из списка
Для выделения из списка подсписка, состоящего из элементов, соответствующих некоторому критерию, используется функция grep:
grep блок список
grep выражение список
Это аналог команды grep операционной системы Unix. Функция вычисляет блок команд или выражение для каждого элемента списка (при этом специальная переменная $_ равна очередному элементу списка) и создает подсписок из элементов, для которых вычисленное значение соответствует условию истина (то есть отлично от нуля, пустой строки, и так далее).
Обычно grep использует поиск по шаблону, как, например, в следующей строке, где создается подсписок из букв, которые не являются буквой "x":
print grep (!/x/, a, b, x, d);
abd
Более подробно о поиске по шаблону вы узнаете из главы 6, но, как видно уже сейчас, функция grep предоставляет мощный инструмент для создания из списков подсписков, основываясь на определенном критерии поиска.
Скалярный и списковый контексты
Скалярный и списковый контексты — это два основных контекста данных в языке Perl. Очень важно понимать разницу между ними. Мы будем постоянно встречаться со скалярным и списковым контекстами в этой книге.
Когда Perl ожидает получить список, он рассматривает данные в списковом контексте, а когда скалярное выражение — в скалярном. В результате, когда данные предполагаются в виде списка, они и трактуются как список. Соответственно, когда данные предполагаются в виде скалярного выражения, они трактуются как скаляр.
Другими словами, то, как именно интерпретируются данные, при программировании на Perl определяется неявным образом из контекста, в котором эти данные используется, и не задается в явной виде с помощью программного кода. Например, если вы работаете с функциями, которые используют аргументы-списки или возвращают значения-списки, то эти значения автоматически интерпретируются как списки.
В скалярном контексте список преобразуется в скаляр (обычно — в последний элемент списка, см. следующий раздел), а в списковом контексте скаляр превращаются в список из одного элемента. Однако нужно заметить, что в Perl нет единого правила, определяющего преобразование данных при переходе из одного контекста в другой. Например, при переходе из спискового контекста в скалярный одни операторы могут подставлять число элементов списка, который должен был бы быть при списковом контексте, другие — возвращают первое значение списка, третьи — возвращают последний элемент списка, а некоторые даже возвращают число успешно проведенных операций над списком. Это может показаться сложным, но обычно переходить от одного контекста к другому (особенно от спискового к скалярному) не требуется, так что вряд ли слишком часто придется заострять внимание на этих деталях.
Форсирование скалярного контекста.
Функция scalar требует интерпретации выражения в скалярном контексте (при этом в Perl нет парного оператора, вынуждающего интерпретировать выражение в списковом контексте). Функция scalar используется так:
scalar выражение
Например, можно вывести список (1, 2, 5) в списковом контексте:
print (1, 2, 5);
125
Если вы используете функцию scalar, то она вынудит интерпретировать список в скалярном контексте. То есть будет возвращен последний элемент списка:
print scalar (1, 2, 5);
5
Функция scalar возвращает последний элемент списка, эмулируя тем самым поведение оператора-запятой языка С. Он ведет себя точно также, — а именно, возвращает последнее вычисленное выражение в списке выражений, разделенных запятыми. То же самое происходит при присвоении скалярной переменной выражения-списка:
$a = (1, 2, 5);
print $a;
5
Кроме присвоения переменной-скаляру, скалярный контекст для данного списка можно форсировать и менее элегантно, — выполнив над списком арифметическую операцию (например, прибавив ноль оператором сложения +).