ЯЗЫК Perl И CGI-ПРОГРАММИРОВАНИЕ

Содержание

Введение
Типы переменных и разыменовывающие символы
Зависимость встроенного типа данных от контекста
Одиночные и двойные кавычки. Интерполяция
Выполнение команд операционой системы и запуск exe-файлов
Операции над скалярными величинами
Оператор присваивания
Оператор безусловного перехода goto
Условные операторы
Операторы цикла
Управление циклом
Списки и массивы
Хеши или ассоциативные массивы
Регулярные выражения
Файлы
Модуль CGI
Базы данных. Модули Win32::ODBC и DBI
Области видимости имён
Подпрограммы и функции
Жёсткие и символические ссылки
Создание собственного модуля
Библиотека модулей LWP
Графическая библиотека GD
Документирование на языке POD

Введение

Язык Perl (Practical Extraction and Report Language - язык практических извлечений и отчётов) хорошо приспособлен для обработки текстовой информации. После появления всеминой паутины (WWW - World Wide Web) Perl стал широко применяться для создания динамических страниц (веб-документов). Для взаимодействия между программой, генерирующей по запросу пользователя динамическую страницу, и веб-сервером разработан специальный стандарт интерфейса, получивший название CGI (Common Gateway Interface — общий интерфейс шлюза). Написание программ с использовантем CGI называется CGI-программированием. Общий термин для процесса создания динамических страниц - веб-программирование. Программы на Perl обычно называют скриптами.

Автор языка Perl - Ларри Уолл (Larry Wall), лингвист по образованию. Образование Ларри Уолла проявилось в том, что в Perle наиболее широко применяется характерная для обычных языков (русского, английского) контекстная зависимость. Вот пример двух операторов присваивания с одинаковой правой частью:

@Array2=@Array1;
$L=@Array1;

В первом операторе создаётся копия массива @Array1. Во втором - вычисляется длина этого массива.

Первая версия Perl была официально представлена 18 декабря 1987 г. Perl 5 появился в октябре 1994 г. Разработка Perl 6 началась в 2000 году, и с переменной эффективностью продолжается и по сей день.

Бытует мнение, что программы на Perl очень трудно читаются. Это не совсем так. Сложность программы на Perl адекватна сложности решпемой задачи и квалификации программиста. Perl по синтаксису похож на "C", но обдадает чертами и многих других языков, так как Ларри Уолл стремился использовать все достижения программирования.

Простейшая программа на Perl:

print "Здравствуйте";

Скорее всего в репутации Perl как очень сложного языка "виноваты" регулярные выражения.

Рассмотрим пример использования регулярного выражения для замены в строках массива тегов <DIV> и <\div> на <H2> и <\h2> соответственно.

$Ar[0]='<DIV style="position:relative;text-align:center;width:97.8%;font-size: 24px;">Грибы</div>';
$Ar[1]='<DIV style="position:relative;text-align:center;width:70%;color:red;">Ягоды</div>';
foreach $str (@Ar)
{	$str=~s/<DIV.*?>(.*)<\/div>/<H2>$1<\/h2>/i;
	print "$str\n";
}
# *************Р е з у л ь т а т ******************
<H2>Грибы</h2>
<H2>Ягоды</h2>

Тем, кто не знает регулярных выражений, оператор

$str=~s/<DIV.*?>(.*)<\/div>/<H2>$1<\/h2>/i;

покажется бессмысленым набором значков, но выражение /<DIV.*?>(.*)<\/div>/ выглядит в точности так же и на языке PHP, созданном как более лёгкая алтернатива языку Perl. Дело в том, что для записи регулярных выражений существует специальный язык, который встраивается в языки программирования или реализуется в виде библиотек.

Правильно оформленная программа (скрипт) на Perl должна содержать в себе документацию, которую можно распечатать в любой момент. Для разметки документации, находящейся в тексте скрипта, служит спциальный язык POD. В общем случае, для написания Perl-скриптов используются три языка:

POD можно использовать для многострочных комментариев. Для комментария в одной строке служит символ #, вся часть строки после которого игнорируется транслятором Perl. Лексема __END__, написанная в начале строки, заставляет транслятор пропускать все строки после неё. Рассмотрим пример, содержащий все виды комментариев.

=head1 NAME
Пример программы на языке Perl
=head1 DESCRIPTION
Вычисление суммы пяти первых
членов натурального ряда
=cut
$s=0; # $ - признак (префикс) скалярной переменной
for($i=1;$i<=5;$i++)
{ $s+=$i;}
print "Сумма пяти первых членов натурального ряда S=$s\n";
#  В строке, заключённой в двойные кавычки, перед печатью производится 
#подстановка значения переменной $s (операция интерполяции)
__END__
Результат:
Сумма пяти первых членов натурального ряда S=15

В примере между лексемами =head1 и =cut находится очень короткая документация. Эти лексемы называются директивами языка POD.

Типы переменных и разыменовывающие символы

Perl - язык свободной формы. Фразы в Perl состоят из лексем.

Определение 1. Лексема - это последовательность символов с единицей смыслового содержания. Внутри лексемы не должно быть пробела.

В Perl различаются идентификатор и имя переменной .

Определение 2. Идентификатор - это лексема, которая начинается с английской буквы или символа подчёркивания и содержит английские буквы, цифры и символ подчёркивания.

Определение 3. Имя переменной состоит из разыменовывающего символа и дентификатора

В Perl понятия переменная и тип переменной отличаются от аналогичных понятий в языке "С". Переменная каждого типа имеет свой разыменовывающий символ (префикс). В табл.1 показано соответствие между типами переменных и разыменовывающими символами.

Таблица 1. Типы переменных и разыменовывающие символы
ТипРазыменовывающий
символ
ПримерПримнчание
Скаляр$$summa, $Ar1[5], $Ar2{'red'} 
Массив@@Ar1индексированный массив
Хеш %%Ar2ассоциативный массив
Подпрограмма&&sub5Как правило,
не используется
Typeglob**bodyлюбой тип
(применяется для
описания метаданных)

$ - от scalar, стилизованное S.

@ - от array, стилизованное a.

Разыменовывающие символы исключают конфликт имён переменнных с ключевыми словами языка.

Зависимость встроенного типа данных от контекста

Скаляры, элементы массивов и хешей принимают скалярные значения. В памяти компьютера скалярное значение независимо от языка программирования может храниться в виде

Строка, целое число и число с плавающей запятой называются встроенными типами данных. В таких языках как "С" или Pascal необходимо перед испльзованием явно объявить встроенныый тип данных (integer, real и т.д.). В языках с явным объвлением встроенный тип данных называют просто типом данных. После объявления типа переменная на всё время выполнения программы остаётся с этим типом.

Часто в зависимости от контекста удобно рассматривать скаляр то как число, то как строку. Приведём пример изменения встроенного типа скаляра в зависимости от контекста.

$v0=0.253;          # $v0 - real8, вес одного яблока
$v5=$v0*5;          # $v5 - real8
@c=split(/\./,$v5); #$v5 - строка
print "Пять яблок весят $c[0] кг $c[1] г.\n";
__END__
Результат:
Пять яблок весят 1 кг 265 г.

Скаляр $v5 во второй строке имеет вещественный встроенный тип. В функции split() скаляр $v5 рассматривается как строка, содержащая точку ("1.265") и расщепляется на две подстроки "1" и "265", которые заносятся в массив @c.

Другие примеры зависимости встроенного типа результата от вида операции и типов операндов:

$a=2;                 #целое
$a1=3.1e-5;           #real8
$c=75.35;             #real8
$b=$a+$a1;            #$b=2.000031 real8
# "." (точка) - операция конкатенации (объединения) строк
$st=$a.$a1;           #$st=23.1e-5
$c=$a." - это число"; # $c = "2 - это число"
$w=lenght($c);        #длина строковой переменной $c - 13 байт
$d=$a/3;              # 0.666... - real8 - 17 знаков, считая точку
$z=lenght($d);        #$z=17

Одиночные и двойные кавычки. Интерполяция

Напечатаем один и тот же текст, заключив его сначала в одиночные кавычки, а затем в двойные:

$a=2; $b=5; $c=$a**$b;
print '$a в степени $b равно $c';
#напечатается
#   $a в степени $b равно $c 
print "$a в степени $b равно $c";
#напечатается
#   2 в степени 5 равно 32 

Текст в одиночных кавычках напечатался без изменений, а в тексте с двойными кавычками произошла замена имён переменных их значениями.

Определение 1. Операция замены в строке, заключённой в двойные кавычки, имён переменных их значениями называется интерполяцией

Определение 2. ESCAPE-последовательность - последовательность символов, на место которой подставляется определённый символ.

В Perl часто используются Escape-последовательности \t (табуляция) и \n (конец строки). В строке, заключённой в одиночные кавычки, ESCAPE-последовательности воспринимаются как обычные последовательности символов, а в строке в двойных кавычках происходит подстановка (интерполяция):

print '\n 1. Заяц.\n 2. Волк.';
#Напечатается
#   1. Заяц.\n 2. Волк.\n
print "\n 1. Заяц.\n 2. Волк.";
#Напечатается
#   1. Заяц.
#   2. Волк.

Чтобы запретить использование символа "\" в качестве признака начала ESCAPE-последовательности, нужно перед "\" поставить ещё один "\":

print "\\t - табуляция \n \\n - конец строки \n";
#Напечатается
# \t - табуляция
# \n - конец строки

Операторы кавычек

Кавычки можно заменить специльными функциями.
Вместо одиночных кавычек используется функция q(стока).
Вместо двойныч кавычек используется функция qq(стока).
Вместо обратных кавычек "`" используется функция qx(стока).
Примеры функций q() и qq().

$a=5;
print 'число $a ',q(число $a );
#Напечатается
#  число $a число $a
print "число $a ",qq(число $a );
#Напечатается
#  число 2 число 2

Использование обратных кавычек и функции qx() описано в разделе Выполнение команд операционой системы и запуск exe-файлов.

Константы

В Perl константы объявляются как функции, выполняемые на этапе компиляции с помощью модуля constant. Модуль, выполняемый на этапе компиляции, называется прагмой.

Пример объявления констант PI (6 знаков), pi (14 знаков) и e.

use constant PI=>3.14159;
use constant pi=>4*atan2(1,1);
use constant e=>exp(1);
print 'PI='.PI.' pi='.pi.' e='.e."\n";
__END__
Результат
PI=3.14159  pi=3.14159265358979  e=2.71828182845905

Выполнение команд операционой системы и запуск exe-файлов

Язык Perl эффективен при обработке текстовой информации, а языки "С" и в особенности FORTRAN с оптимизирующим транслятором лучше использовать для задач с большим количеством вычислений. Можно построить программный комплекс (систему), состоящий из модулей, написанных на разных языках. На Perl целесообразно написать подсистему ввода-вывода, а на "С" - ядро системы, выполняющее большой объём вычислений. После ввода исходных данных необходимо из программы на Perl вызвать внешнюю программу (ядро).

В Perl для вызова внешних программ есть три функции:

Выполнение этих функций зависит от операционной системы. В приведённых примерах предполагается, что операционная система принадлежит семейству Windows.

Функция qx() входит в число функций, использующихся для замены кавычек ( q(), qq(), qw() ). Вместо $a=`gra.exe` можно написать $a=qx(gra.exe), где gra.exe - внешняя программа. Функция qx() возвращает результат либо в скаляр, либо в массив:

@A=`dir C:`; #читается и заносится в массив @A корневой каталог диска C:
#@A=qx(dir C:); - то же самое
#Печать массива @A
foreach $b (@A)
{ print "$b\n";}
$a=`dir C:`; #вывод результатов в скаляр
print $a;

Функция system() отличается от qx() тем, что возвращает статус выполнения программы, а результаты выводятся на системное устройство.

Пример

$a=system("dir C:"); # $a=0 и на экран выводится корневой каталог диска C:
$a=system("dir R:"); # $a=256, диска R в системе нет

Функция exec() отличается от system() тем, что возврат в вызывающую программу не происходит.

Пример

exec(dir C:");
#Следующие команды не выполнятся
exec("gra.exe");
print "Конец программы";

Операции над скалярными величинами

Операции над скалярными величинами, как и во многих языках программирования, делятся на:

Арифметические операции

Язык Perl характерен тем, что в нём используется многое удачное из более ранних языков программирования. Например, обозначение операции возведения в степень "**" такое же, как в FORTPAN-e, а автоинкремент "++" и автодекремент "--" такие же, как в "С". В Perl используются следующие арифметические операции:

+ сложение,
- вычитание,
* умножение,
/ деление,
% деление по модулю,
** возведение в степень,
++ автоинкремент,
-- автодекремент.

Строковые операции

. (точка) - конкатенация, соединение двух строк,

x - умножение или повторение

Примеры

$st1 = 'Операция';
$st2 = ' над строками';
$st1 = $st1.$st2; # $st1 = Операция над строками
#или короче
$st1 .= $st2;

$st ='-';
$s5 = $st x 5 # $s5 = -----

Операции сравнения

В Perl различается сравнение скаляров в числовом и в строковом контексте, так как от контекста зависит результат сравнения. Ниже приведён пример, в котором два числа в текстовом контексте равны, а в строковом нет.

$a=3.1; $b='3.10';
if($a == $b){print "a равно b \n";} # Сравнение в числовом контексте
else {print "a НЕ равно b \n";}
#Напечатается 
# a равно b
if($a eq $b){print "a равно b \n";} # Сравнение в строковом контексте
else {print "a НЕ равно b \n";}
#Напечатается 
# a НЕ равно b

В табл. 2 приведенны обозначения операций сравнения в числовом и строковом контексте.

Таблица 2. Операции сравнения
Название
операции
Обозначение
Для чиселДля строк
Равно ==eq
Не равно !=ne
Меньше <lt
Больше >gt
Меньше или равно <=le
Больше или равно>=ge
не равно (результат со знаком) <=>cmp

Результат операции $a <=> $b равен +1, если $a > $b, нулю, если $a == $b, -1, если $a < $b.

Логические операции

Любая скалярная величина, не равная нулю или пусто, в логическом контексте считается истиной. Только нуль или пусто в логическом контексте принимает значение ложь. Такое толкование логического контекста позволяет упростить программу. Предположим, что скрипт, генерирующий динамическую страницу, получает от пользователя из экранной формы содержимое полей ввода. Пользователь имеет право либо заполнять поле FIO, либо оставить его пустым. Приведём фрагмент скрипта, в котором проверяется, введено ли FIO.

$fio=param('FIO'); # значение фамилии присваивается переменной $fio
#Если $fio не равно '', то выведем сообщение 
if(!$fio){ print "Фамилия неизвестна" } #!$fio - нет фамилии
#Неопытные программисты пишут так:
if($fio != ''){ print "Фамилия неизвестна" }

Логичические операции в порядке убывания приоритетов:
! логическое НЕ
&& логическое И
|| логическое ИЛИ
not логическое НЕ
and логическое И
or логическое ИЛИ
xor логическое исключающее ИЛИ

Приоритеты && и || выше чем у операции присваивания, а у and и or - ниже, поэтому в операторе

$logic = 5>2 && 4<2;

переменная $logic принимает значение пусто, т.е. ложь, а в операторе

$logic = 5>2 and 4<2;

переменная $logic принимает значение единица, т.е. истина. Чтобы не задумываться о приоритетах операций, можно пользоваться скобками:

$logic = (5>2 and 4<2); # $logic=1

Операции поразрядного сравнения

& логическое И
| логическое ИЛИ
^исключающее ИЛИ

Операции поразрядного сравнения производятся над 32-разрядными числами (строго говоря, разрядность зависит от компьютера). Сначала числа преобразуются в целые, а затем производится операция.

Примеры

$x = 1.2 & 4; #$x=0
# 1.2 -> 1
# 0 . . . 0001
# 0 . . . 0100
# 0 . . . 0000

$y = 5.2 & 7.4; # $y=1012=5
#5.2 -> 5 7.4 -> 7
#0 . . . 0101
#0 . . . 0111
#0 . . . 0101

Оператор присваивания

В Perl, как и в "С", имеется два вида оператора присваивания : простой и сложный. Простой оператор присваивания имеет синтаксис

переменная = выражение;

например

$a = cos($b+$c);

Примечание. Следуя формально принятой в программировании терминологии, нужно называть оператором значок "=", а выражение $a = cos($b+$c); - операцией. Такая терминология тоже не слишком удачна, так как общепринятое значение слова операция - действие, процесс, а не выражение. Логично, понятно предложение: "оператором $a = cos($b+$c); присваивается переменной $a значение выражения cos($b+$c).

Сложный оператор присваивания используется вместо такого простого оператора, в левой и правой частях которого размещена одна и та же переменная. Например, простой оператора присваивания

$a = $a + cos($b+$c);

можно заменить сложным

$a+= cos($b+$c);

Сложный оператор присваивания состоит из двух операторов. Первым может быть любой арифметический, логический, строковый оператор или оператор сравнения, а вторым - простой оператор присваивания. Ниже приводятся примеры различных операторов присваивания.

$a = 2; $b = 3;
$a += $b; # $a=5
$a *= 5; # $a=25
$c=15; $d = 4;
$c %= $d; # $c=3
$c .= " рубля"; # $c= 3 рубля 

Оператор безусловного перехода goto

Рассмотрим два вида оператора goto (в Perl пишется слитно):

goto МЕТКА;
goto список_меток [номер метки в списке];

Оператор goto является потенциальным источником характерной только для него ошибки, которую в больших программах очень трудно обнаружить. Рассмотрим пример программы, в которой имеется всего две метки. Предположим, что программист допустил ошибку, указав в goto несуществующую метку. Фрагмент такой программы выглядит примерно так:

. . . . . 
    if($a==$b) goto M1;
. . . . . 
. . . . . 
    goto M2;
M3: $c=3;
. . . . . 
. . . . . 
    $d=9;
M2: $L=@Ar;
. . . . . 
. . . . . 

Блок операторов, начиная с оператора $c=3; и заканчивая $d=9; никогда не выполнится. Такие ошибки возникали в программах, написанных на ранних версиях FORTRANa, в которых не было блочного оператора if . . . else. Поэтому программисты были вынуждены использовать в программе сотни меток и иногда их путали. Принципиально можно обойтись без оператора goto, но в некоторых случаях его применение сильно упрощает программу.

Пример использования второго вида оператора goto:

. . . . . 
    $i=0;
. . . . . 
. . . . . 
    $i=1;
. . . . . 
. . . . . 
    goto(("M1","M2","M3")[$i]);
. . . . . 
. . . . .
M1:
. . . . . 
. . . . .
M2:
. . . . . 
. . . . .
M3:
. . . . . 
. . . . .

Если $i=1, то переход произойдёт к метке M1.

Условные операторы

Рссмотрим следующие операторы:

условный оператор ? (вопрос)

Синтаксис:

Условие ? выражение 1 : выражение 2 ,
где Условие - зто выражение, принимающее логическое значение.

Примеры оператора "?"

$a = 2;
$a > 0 ? print "Хорошо" : print "Плохо";
$st = $a > 0 ? "Хорошо" : "Плохо";
print $st;
# В обоих случаях напечатается 	"Хорошо"

Простые условные операторы if и unless

Синтаксис:

выражение if Условие;
выражение unless Условие;

Примеры операторов if и unless

$a = 2;
print "Правильно\n" if $a > 0;
print "Правильно\n" unless $a < 0;
#В обоих случаях напечатается "Правильно"

Составной условный оператор

Рассмотрим синтаксис четырёх вариантов составного условного оператора:

if(Условие) Блок
if(Условие) Блок else Блок
if(Условие) Блок elsif(Условие) Блок
if(Условие) Блок elsif(Условие) Блок . . . else Блок

Под блоком понимается последовательность операторов, заключённая в фигурные скобки. В отличие от "С" в Perl блок заключается в фигурные скобки, даже если он состоит из одного оператора. Последний оператор блока может не заканчиваться точкой с запятой.

Примеры составных условных операторов

# Первый вариант
if($a > $b) { $e = $a }
# Четвёртый, самый полный вариант
if($a < 0)
{  $b = 3;
   $c = 2;
}
elsif($a == 0)
{  $b = 5;
   $c = 1
}
elsif($a > 0)
{  $b = 7;
   $c = 9;
}
else 
{ $b = $c = 2 }

Операторы цикла

В Perl имеются следующие операторы цикла:

В Perl нет оператора переключения switch.
Оператор foreach будет описан в разделе Списки и массивы.

Операторы цикла с предусловием while и until

Синтаксис:

while(Условие) Блок
until(Условие) Блок

Цикл while выполняется до тех пор, пока условие истинно, а until - наоборот, пока условие ложно

Примеры

# Подсчитывается количество выпавших подряд случайных чисел $x<90
$x=0;$i=0;
while($x < 90)
{	$x = rand(100);
	$i++;
}
print "$i $x\n";
$x=0;$i=0;
until($x >= 90)
{	$x = rand(100);
	$i++;
}
print "$i $x\n";
}

Операторы цикла с постусловием do . . . while и do . . . until

Синтаксис:

do Блок while(Условие);
do Блок until(Условие);

Блок в этих операторах всегда выполняется хотя бы один раз, а различие между ними такое же, как между предыдущими операторами while и until.

Примеры

# Если начальное значение $i<6, то подсчитывается сумма $s=$i+ ($i+1)+ . . +5, 
# иначе $s присваивается начальное значение $i 

#Вариант 1. Тело цикла (блок) выполняется 5 раз
$s=0;$i=1;
do
{  $s += $i++;}
while($i<6);
print " s=$s\n"; #s=15, $i=6

#Вариант 2. Тело цикла (блок) выполняется только 1 раз
$s=0;$i=7;
do
{  $s += $i++;}
while($i<6);
print " s=$s\n"; #s=7, $i=8

Оператор for

Синтаксис оператора:

for(переменная цикла = начальное значение; условие выхода; возобновляющее выражение) Блок

Пример

# Посчитывается сумма членов натурального ряда от 1 до 5
$s = 0;
for($i = 1; $i <= 5; $i++) {$s += $i++}
# s=15

Управление циклом

Для управления циклом служат следующие операторы:

Метка ставится перед оператором цикла и даёт имя всему циклу. В теле цикла может быть сколько угодно операторов управления циклом.

Оператор next служит для перехода к следующей итерации, при этом часть тела цикла (блока) после next не выполняется.

Пример

#Просматривается массив имён @Ar. Если встретилось имя Маша,
#то оставшаяся часть тела цикла пропускается
for($i=1; $i<=5; $i++)
{   . . . . 
    . . . .
    if($Ar[$i] eq 'Маша') next;
    . . . . 
    . . . .
}

Оператор next МЕТКА служит для перехода в начало внешнего цикла с меткой. Внутренний цикл прерывается, часть тела внешнего цикла c меткой пропускается.

Пример

#Во нутреннем цикле просматривается массив имён @Ar. Если встретилось имя Маша,
#то происходит переход к метке A:
A:for($k=1; $k<=5; $k++)
  {  . . . . 
     . . . .
     for($i=1; $i<=5; $i++)
     {   . . . . 
         . . . .
         if($Ar[$i] eq 'Маша') next A;
         . . . . 
         . . . .
     }
     . . . . 
     . . . .
  }

Оператор last служит для выхода из цикла.

Оператор last МЕТКА служит для выхода из внешнего цикла с меткой.

Оператор redo служит для повторения тела цикла с начала без изменения переменной цикла.

Оператор redo МЕТКА служит для повторения тела внешнего цикла с меткой с начала без изменения переменной цикла.

Списки и массивы

Определение. Список - упорядоченные скалярные данные, а массив - переменная, содержащая список.

Примеры списков

(1,2,'Мир',3.85)
qw(март апрель май) # вместо ('март','апрель','май')
()		# пустой список

Функция qw() служит для записи элементов списка через пробел и без кавычек. Она упрощает запись списка, уменьшая вероятность ошибок.

В список могут входить элементы разных встроенных типов, поэтому в Perl отпадает необходимсть в используемых в "С" структурах.

Примеры применения конструктора списков

(1..5) # вместо (1,2,3,4,5)
$a = 2; $b = 6;
($a..$b) # (2,3,4,5,6)
('A'..'Z') # Весь английский алфавит

Извлечение элемента из списков

$i=2;
$elem = qw(a b c d e)[$i];   # $elem = 'c'

Все массивы в Perl динамические по умолчанию. Можно добавлять и удалять элементы массива.

Создание массива из пяти элементов:

@a = (1,2,3,"цена","вес");

Нумерация элементов массива начинается с нуля:

$elem = $a[3]; # $elem = "цена"

Добавление элемента:

$a[5] ="цвет";

Массив можно создавать поэлементно:

$b[0]=1;
$b[2]=3;
foreach $x (@b){print "$x\n";}
__END__
Напечатается
1

3
Элемент $b[1] - пустой

Одномерные массивы можно распечатывать в одну строку:

@c = (3.14,2,72)
print "Массив с: @c\n"; # напечатается  "Массив с: 3.14 2,72"

Срезы массива:

@c[2 .. 5] = (1,2,3,4); # в @c добавлено 4 элемента
@d = @c[1 .. 4]; #срез
print @d,"\n"; # 2.72 1 2 3

Функции push() и pop()

Синтаксис:
    push(Array,LIST)
    pop(Array)

Функция push(Array,LIST) вставляет в конец массива Array список элементов LIST.

Пример

@Ar =(1,2,3);
push(@Ar,(4,5));
print "\@Ar= @Ar\n"; #@Ar = 1 2 3 4 5

Функция pop(Array) удаляет последний элемент массива Array.

Пример

$x=pop(@Ar);
print "\@Ar = @Ar, \$x = $x \n"; #@Ar = 1 2 3 4, $x = 5

Функции unshift() и shift()

Синтаксис:
    unshift(Array,LIST)
    shift(Array)

Функция unshift(Array,LIST) вставляет в начало массива Array список элементов LIST.

Пример

@Ar =(1,2,3);
unshift(@Ar,(4,5));
print "\@Ar= @Ar\n"; #@Ar = 4 5 1 2 3

Функция shift(Array) удаляет первый элемент массива Array и возвращает удалённый элемент.

Пример

$x=shift(@Ar);
print "\@Ar = @Ar, \$x = $x \n"; #@Ar = 5 2 3 4, $x = 4

Длина массива. Cкалярный и списочный контекст

@Ar =(1,2,3);
@B = @Ar;  # Списочный контекст. @B - копия масссива @Ar
$n = @Ar;  # Скалярный онтекст. $n=3 - длина массива @Ar
$I = $#Ar; # $I = 2 - наибольший индекс массива @Ar

Двумерные массивы

Двумерный массив - массив, элементами которого являются одномерные массивы.Создадим двумерный массив:

@D =(
      ["a","b"],
      ["c","d","e"],
	  [qw(f g  h)]
     );
print "$D[1][2]\n"; # Напечатается "e" 

При создании двумерного массива можно использовать ранее созданные массивы:

@b = (1,2,3);
@c = (4,5);
@E =(
      [@b],
      [@c],
     );
print "$E[0][2] $E[1][0]\n"; # Напечатается "3 4" 

Подробнее о работе с двумерными массивами рассказывается в разделе Ссылки.

Оператор цикла foreach

Часто возникает необходимость перебрать все злементы массива. Оператор foreach позволяет сделать это, не зная длины массива и не используя индексов элементов.

Синтаксис

foreach переменная(список) БЛОК

Оператор foreach читается так: "Для каждого элемента массива выполнить блок операторов".

Пример

@a = (1 .. 10);
$s=0;
foreach $x(@a) 
{ $s += $x}
print "Сумма чисел 1,2, . . ,10 равна $s\n"; # $s = 55

Переменная $_

В языке Perl есть множество приёмов, позволяющих сократить текст программы. Ларри Уолл в шутку говорит, что такие приёмы потокают лени программистов. Различаются малая и большая лень. Один из приёмов сокращения текста программы - использование специальной переменной $_. Если из контекста ясно, что результат должен быть присвоен скаляру, а этого скаляра в операторе нет, то по умолчанию результат помещается в переменную $_. Этот приём имеет и отрицательный эффект, затрудняя неопытным программистам чтение чужих программ.

Примеры использования $_

@a = (1 .. 10);
foreach (@a)
{$S+= $_;} # Маленькая лень. Суммируются все элементы массива
foreach (@a)
{print} # Большая лень. Распечатывается в одну строку весь массив (ABCD)
#Вывод элементов массива в столбик
foreach (@a)
{print "$_\n";}

Хеши или ассоциативные массивы

В отличие от обычных массивов хеш хранит список пар скаляров, первый из которых называется ключом элемента, а второй - значением. Зная ключ, можно получить значение элемента. Самым простым применением хеша служит словарь для перевода. Составим словарь перевод названий дней недели с русского языка на английский:

%DNI = ("понедельник","Monday",
        "вторник",    "Tuesday",
        "среда",      "Wednesday"
       );
$vt=$DNI{"вторник"}; # скобки - фигурные !!!
print "вторник - $vt\n"; # вторник - Tuesday

Может быть, нагляднее создавать хеш так:

%b = ( "цвет" => "красный",
       "вес"  => "30 г",
       "цена" => 1000
     );

Добавление нового элемента:

$b{k4} = "новый элемент";

Если ключь не имеет русских букв, то заключать его в кавычки не обязательно.

Организация хеша - очень трудная задача. С целью оптимизации времени поиска траслятор организует размещение элементов в особом, неизвестном программисту порядке.

Для выделения ключей в отдельный массив служит функция keys:

@KE = keys(%b); # ключи в @KE не упорядочены

Для упорядочения ключей воспользуемся функцией sort:

@KE = sort keys(%b); 
# или так со скобками привычнее
@KE = sort (keys(%b));
# а так короче
@KE = sort keys %b ;
# количество ключей
$L = @KE;
#или
$L = scalar(keys(%b));
# Функция scalar необязательна
$L = keys(%b);

Просмотр всего хеша:

foreach $k (sort keys(%b))
{  print"b{$k} = $b{$k}\n";}
__END__
Будет напечатано
b{вес} = 30 г
b{цвет} = красный
b{цена} = 1000

Файлы

Операторы, наиболее часто используемые для работы с файлами:

Проверка существования файла

Удобно использовать следующую схему проверки существования файла:

if( -e имя_файла)
{обработка файла}
else
{ print "Файл не найден}

Открытие файла. Оператор open

Синтаксис

open(дескриптор_файла, "режим имя_файла");
Основные режимы:
<  - чтение,
>  - запись,
>> - дополнить существующий файл, если файла нет, то создать новый

Пример открытия файла для чтения

$fi = 'Edit3.pl';
open(F1,"< $fi") || die("Файл $fi не открылся");
#Или
open(F1,"< Edit3.pl") || die("Файл Edit3.pl не открылся");
#Заметьте, строковая константа Edit3.pl не заключена в кавычки

Закрытие файла

Синтаксис

close дескриптор_файла; 

Чтение записей из файла. Оператор < >

Синтаксис

Скалярный контекст. Читается одна запись
  скаляр = <дескриптор_файла>;
Cписковый контекст. В массив читается весь файл
  массив = <дескриптор_файла>;

Примеры чтения

#Читается одна запись
$str = <F1>;
#В массив читается весь файл
 @Ar = <F1>;

Записей в файл. Оператор print

Синтаксис

print <дескриптор_файла> список_вывода;

Пример

$a = 2;
$b = 4;
#Весь список вывода в кавычках
print F1 "$a\t$b\n";
#Более длинно
print F1 $a,"\t",$b,"\n";

Двоичный файл. Операторы binmode и read

Синтаксис

binmode дескриптор_файла;
read (дескриптор_файла, переменная, размер_буфера);

Операторы для работы с двоичными файлами должны быть расположены в следующем порядке:

open
binmode
операторы read или print

Пример копирования изображения

open(GIF1,"> graphic1.gif"); #открыть файл для записи
binmode GIF1;
open(GIF,"< graphic.gif");   #открыть файл для чтения
binmode GIF;
while(read(GIF,$buf,1024))
{ print GIF1 $buf;
}

Другой пример работы с двоичным файлом приведён в разделе Графическая библиотека GD

Пример скрипта, выводящего в окно браузера содержимое текстового файла

В текстовом файле Spisok.txt хранится таблица, состоящая из четырёх столбцов, разделённых символом табуляции \t. Таблица имеет следующий вид:

    ФИО            телефон     Город         Дом_ улица_кв
Алепский Евгений  139-23-77   Новгород     Казанская ул.7, кв24
Губанова Мария    143-67-67   С-Петербург  Московский пр, д 34, кв 57
 . . . . . . . . . . . . . . . .  . . . . . . . .  . . . . . . . .
Яковлева Ольга     534-51-25  С-Петербург  Смоленская ул., д.12, кв 38

Файле Spisok.txt хранится в каталоге C:/WebServers/home/KafI5.loc/www/Kam.loc/, а скрипт - в каталоге C:/WebServers/home/KafI5.loc/cgi/.

Скрипт состоит из трёх последовательно выполняющихся частей:

Текcт скрипта

#!/usr/bin/perl
use CGI::Carp qw(fatalsToBrowser);#Для вывода сообщений об ошибках в окно браузера 
$fil='Spisok.txt';
chdir '..\www\Kam.loc'; #переход в  каталог, содержащий файл Spisok.txt
print "Content-type: text/html\n\n"; #Без этой строки данные не будут выводиться в окно браузера
print "<HTML><BODY>";
#**** Проверка существования файла *****
if(-e $fil){Obrabotka();} 
else
{  print "файл $fil не найден.";}
print "</body></html>\n";
#****** Подпрограмма чтения текстового файла ********
sub Obrabotka
{ #**** чтения в цикле записей файла и формирования массивов фамилий и телефонов ****
    open(F1,"< $fil"); #Открытие файла для чтения
    $i=0;
    while (<F1>)       # чтение по одной записи в переменную $_
    {  chomp;         # удаление символов конца строки
       @_=split(/\t/);# расщепление строки на поля по символу 
                      #табуляции. Результат хранится в @_
       $fio[$i]=$_[0]; #$_[0] элемент массива @_  
       $gor[$i]=$_[2];
       $i++;
    }
    close F1;
  #*** формирования динамического HTML-документа и передачи его в браузер ***
    print <<EOT;
    <table border=1 style="margin-left:50px;">
    <caption style="text-align: center;font-size:110%;font-weight:bold;">
    Таблица3. Список всех клиентов
    <tr><th>ФИО<th>Город
EOT
   #Вывода всех строк таблицы
   for($k = 1; $k < $i; $k++)
   {  print "<tr><td> $fio[$k]<td> $gor[$k] \n"; }
   print "</table>\n";
}

Результаты выводятся в браузер в виде преставленной ниже табл.3.

Таблица3. Список всех клиентов
№ п.п.ФИОГород
1 Алепский Евгений Новгород
2 Губанова Мария С-Петербург
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31 Яковлева Ольга С-Петербург

Модуль CGI

Стандартный модуль CGI ( Handle Common Gateway Interface requests and responses - обработка запросов и ответов через общий интерфейс шлюзов) служит для облегчения написания скриптов, генерирующих динамические HTML-страницы по запросам пользователей всемирной паутины (WWW). Предоставляемые модулем CGI средства используются в двух стилях. В объектно-ориентированном стиле нужно создать объект, а затем использовать подходящие методы. Более простой в написании, но не менее эффектиный стиль - использование обычных функций. Каждому методу в модуле CGI соответствует функция. Рассмотрим три функции (метода):

Кроме того, рассмотрим пример использования методов автоматической генерации HTML-кода.

param() - приём параметров, посланных в запросе пользователя

Функция param() сама определяет, какой метод (GET или Post) был использован при передаче параметров на веб-сервер. Пусть на веб-сервер поступили параметры predmet и ocenka. Присвоим их значения перемнным $pred и $oc.

Объектно-ориентированный стиль

 #!/usr/bin/perl
 use CGI "param";  #подключение модуля
   $QString =new CGI; #Создание объекта
   $pred=$QString->param("predmet");
   $ocen=$QString->param("ocenka");

Cтиль c функцией

 #!/usr/bin/perl
 use CGI "param";  #подключение модуля
 $pred = param("predmet");
 $ocen = param("ocenka");

papam без параметра возвращает список имён параметров, поступивших от браузера.

@name = QString->param;
Или
@name = >param;

Примеры передачи параметров можно посмотреть в разделе PERL. Лабораторные работы в лабораторных работах 1 и 3.

redirect() - перенаправление на другую страницу

Пусть при $gorod = 'Москва' необходима страница Kreml.html, а при $gorod = 'Петербург' - страница Ermitag.html,

Объектно-ориентированный стиль

 #!/usr/bin/perl
 use CGI qw(param redirect);   #подключение модуля
 $QString =new CGI; #Создание объекта
 . . . . . 
 if($gorod eq 'Москва')
 {   print $QString->redirect("Kreml.html");
 }
 else
 {   print $QString->redirect("Ermitag.html");
 }

Cтиль c функцией

 #!/usr/bin/perl
 use CGI qw(param redirect);  #подключение модуля
 . . . . . 
 if($gorod eq 'Москва')
 {   print redirect("Kreml.html");
 }
 else
 {   print redirect("Ermitag.html");
 }

upload() - передача файла с компьютера пользователя на веб-сервер

Для передачи файла теги <FORM> и <INPUT> должны быть записаны так:

<FORM METHOD=POST ACTION="cgi/filIzForm.pl" enctype="multipart/form-data">
<INPUT type=file name=fil>

Скипт, принимающий файл

#!\usr\bin\perl
use CGI qw(param upload);
$fil=param("fil"); # Имя передаваемого файла
$fi=upload("fil"); #переменная $fi содержит дескриптор полученного файла
#Объектный стиль
#$query=new CGI ;
#$fil=$query->param("fil");
#$fi=$query->upload("fil");
while(<$fi>)
{   print"$_<BR>";}

Пример автоматического создания HTML-документа

В модуле CGI есть большое количество методов для автоматической разметки HTML-документа. Используя методы header, start_html, h1 и end_html, создадим страницу, состоящую из одной строки Здравствуй! Мир.:

#!\usr\bin\perl
use CGI;                             # загрузка CGI-методов
$q = new CGI;                        # создание CGI-объекта
print $q->header,                    # создание HTTP-заголовка
      $q->start_html('hello world'), # start the HTML
      $q->h1('Здравствуй! Мир.'),    # заголовок 1-го уровня     
      $q->end_html;                  # конец HTML-документа
__END__
*** Р Е З У Л Ь Т А Т Ы ***
Content-Type: text/html; charset=ISO-8859-1

<!DOCTYPE html
   PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>hello world</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<h1>Здравствуй! Мир.</h1>
</body>
</html>

Сгенерированные по умолчанию параметры страницы могут не подойти. Чтобы, например, изменить кодировку с iso-8859-1 на windows-1251, нужно переписать $q->header:

$q->header(- charset => 'windows-1251')

Этот пример показывает, что не всегда средства автоматизации уменьшают время программирования. Применение методов автоматического создания HTML-документа требует знания и этих методов со всеми их параметрами и языка HTML. Легче напрямую создавать страницу на HTML. Обычно все страницы сайта содержат множество одинаковых фрагментов. Написав одну страницу, программист выделяет общие для всех страниц сайта фрагменты и либо копирует их в новые страницы, либо сохраняет в отдельных файлах и затем вставляет в новые страницы директивами языка SSI (Server Side Includes — включения на стороне сервера)

Базы данных. Модули Win32::ODBC и DBI

Базы данных широко используются в информационных системах. Можно сказать, что информацтонная систем - это база данных с удобным интерфейсом. Информационные системы строятся по архитектуре клиент-сервер. Для информационных систем, построенных в виде сайтов в качестве клиентской части используется любой браузер. Поэтому часто в виде сайтов строятся корпоративные инфоормационные системы, эксплуатируемые во внутренних сетях (Intranet).

Скрипт, генерирующий ответ на запрос пользователя, пишется по следующей схеме:

Пример скрипта, использующего модуль Win32::ODBC

#!/usr/bin/perl
#***** Пример работы с базой данных через модуль Win32::ODBC ***
use CGI::Carp qw(fatalsToBrowser);#Для вывода сообщений об ошибках в окно браузера 
use Win32::ODBC;
use CGI qw(param);
print "Content-type: text/html\n\n";
print "<html>\n";

#*** Получение параметра запроса ***
$fio=param("fio");

#*** Связь с базой данных *****
if(!($db=new Win32::ODBC("dsn=Klient")))
{	print "База не открылась</html>\n";
	exit;
}
#**** Формирование и выполнение запроса ****
$sq="SELECT * FROM FIO_adr WHERE fio LIKE '$fio%'";
$db->Sql($sq);
$k=0;
while($db->FetchRow())
{   ($Fio[$k],$tel[$k],$gor[$k],$adr[$k])=$db->Data;
    $k++;
}
if($k==0)
{  print "Данных, удовлетворяющих запросу, нет";}

#***** Формирование HTML-документа *****
else
{  print '<TABLE border=1><CAPTION>Список клиентов'
        .'<TR><TD>ФИО<TD>Телефон<TD>Город<TD>Улица, дом ,кв.';
   for($i=0;$i<$k;$i++)
   {print "<TR><TD>$Fio[$i]<TD>$tel[$i]<TD>$gor[$i]<TD>$adr[$i]";
   }
   print "</table>";
}
print "</html>\n";

Пример скрипта, использующего модуль BDI


=Comment Пример работы с базой данных MySQL с помощью
модуля DBI
ВНИМАНИЕ! Должен быть запущен Apach  и вместе с ним MySQL server
=cut

use DBI;
$data_source="dbi:mysql:alfa"; #alfa - имя базы данных
$user="root";
#$password="kbh";
$password="";
$dbh = DBI->connect($data_source, $user, $password)
           || die $DBI::errstr;
$statement="Select * From student";
$sth = $dbh->prepare($statement);
$rv = $sth->execute;     #$rv - количество выбранных строк
while(@row_ary  = $sth->fetchrow_array)
{   print "@row_ary\n" ;  }

Области видимости имён

Переменные с лексической областью видимости. Объявление my

Все переменные делятся на глобальные и лексические. Лекссические переменныые называются также закрытыми переменными и переменными с лексической областью видимости. Глобальные переменные доступны во всей программе, а область видимости лексической переменной ограничена.

Для объявления лексических переменных служит оператор my.
Синтаксис оператора my

 my переменная;
или
 my переменная = выражение;
или
 my список_переменных;
или
 my список_переменных = массив;

Переменная, объявленная как my в блоке, доступна в этом блоке и во всех блоках, охватываемых этим блоком . Вне этого блока она не видна и при выходе из него лексическая переменная уничтожается. Если объявление my находится вне блоков, то область видимости - весь файл.

Пример

#**** начало файла ****
my $a1; # первая лексическая переменная видна во всём файле
$a1 = 5;

{   #*** Блок Б1 ****
    print "$a1\n"; # $a1=5 - # первая лексическая переменная
} 

{  #*** Блок Б2 ****
    print "$a1\n"; # $a1=5 
    my $a1 = 10; # $a1 - вторая закрытая (лексическая) переменная
                 # её область видимости - Блок Б2
    print "$a1\n";   # $a1=10
    
    { #*** Блок Б3 ****
        print "$a1\n";   # $a1=10
        my $a1 = 33; # $a1 - третья закрытая переменная,
                     # её область видимости - Блок Б3
        print "$a1\n";   # $a1=33
    }
    print "$a1\n";   # $a1=10 - вторая лексическая переменная
}
print "$a1\n"; # $a1=5 - первая лексическая переменная
my($e,@Ar,%Ass); #объявление в одном операторе скаляра, массива и хеша
my ($c,$d) = (3,4);
print "c = $c d = $d\n"; #c = 3  d = 4

#**** конец файла ****

Переменная $a1, объявленная в каком-либо блоке как my, видна во всех вложенных в него блоках, если в них нет переопределения my $a1.

При вставке в файл другого файла с помощью require или use переменная, объявленная как my во вставляемом файле, не видна в главном файле.

Пример вставки с помощью require

Вставляеммый файл

my $a1 = 5;
$a2 = 25 #глобальная переменная

Главный файл со скриптом

my $a1 = 10;
print "$a1\n"; #a1 = 10
require "yyyy.pl";
print "$a1\n"; #a1 = 10
print "$a2\n"; #a2 = 25

Cкрипт после вставки

my $a1 = 10;
print "$a1\n"; #a1 = 10
{  my $a1 = 5;
   $a2 = 25 #глобальная переменная
}
print "$a1\n"; #a1 = 10
print "$a2\n"; #a2 = 25

Примечание. Вставка с помощью use происходит при трансляции, а с помощью require - при выполнении скрипта, поэтому распечатать или увидеть скрипт после вставки невозможно

Глобальные переменные и пакеты

Глобальная переменная существует с момента объявления до окончания выполнения программы и видна во всей программе. В одной программе может быть несколько глобальных переменных с одинаковым именем. Следующий пример показывает, как отличить такие переменные.

$a1=5; # объявлена глобальная переменная $a1, 
       # принадлежащая принадлежащая пакету main
{ package pack1;
  print "a1=$a1 ***\n"; #$a1 в пакете pack1 ещё не объявлена
                        #поэтому напечатается "a1= ***"
  $a1=10; # Обявление переменной $a1, принадлежащей пакету pack1
  print "a1=$a1 main::a1=$main::a1\n";
  # Напечатается a1=10 main::a1=5
}
print "a1=$a1 pack1::a1=$pack1::a1\n";
# Напечатается a1=5 pack1::a1=10

В примере две переменные с одинаковым именем $a1. Единственный блок (он ограничен фигурными скобками) начинается оператором package pack1;. Такой блок называется пакетом. Первое появление переменной в пакете служит её объявлением. Внутри пакета к такой переменной можно обращаться по обычному имени. Вне пакета нужно ипользовать квалифицированное имя. В примере два квалифицированных имени: $main::a1 и$pack1::a1, позволяющие отличать переменные $a1, принадлежащие разным пакетам.

Cинтаксис квалифицированного имени

имя_пакета::имя_переменной

Весь файл является пакетом с именем main. Имена, объявленные в пакете, хранятся в хеше с тем же именем. Хеш, соответствующий пакету main, имеет имя %main::, а хеш пакета pack1 - %pack1::.

Хеш, хранящий имена называется таблицей имён.
Таблица имён является хранилищем содержимого пакета.

Объявление our и прагма strict "vars"

Прагмы отличаются от модулей тем, что выполняются на этапе компиляции. Прагма strict "vars" обязывает при объявлении глобальной переменной использовать оператор our.

Пример

use strict "vars";
our $a1=5;
#$b1=9; #Ошибка, так как $b1 не объявлена как our или my
{ package pack1;

  print "a1=$a1\n"; #Видна переменная $a1 из пакета main
  our $a1=10;       #Теперь для $a1 из пакета main
                    #нужно использовать квалифицированное имя
  print "a1=$a1 main::a1=$main::a1\n";
}
print "a1=$a1 pack1::a1=$pack1::a1\n";
require "yyy.pl";
print "a1=$a1 yyy::a1=$yyy::a1\n";
__END__
Файл yyy.pl

$a1=25;
package yyy;
$a1=12;
1;
 ****** Результаты *********
a1=5
a1=10 main::a1=5
a1=5 pack1::a1=10
a1=25 yyy::a1=12

Прагмы имеют лексическую область видимости. Во внутреннем блоке можно отменить прагму:

use strict; 
. . . . . .
{no strict   #отмена действия strict
 . . . . . .
}

Подпрограммы и функции

В Perl подпрограммы и функции не различаются. Функции можно не объявлять, но для облегчения работы транслятора можно сделать объявление.

Синтаксис объявления функции

sub имя_функции;

Для того чтобы сделать объявление функции обязательным, служит прагма use strict "subs". Функция хранит передаваемые формальные параметры в специальном массиве @_ и возвращает результат последнего оператора.

Пример. Функция, возвращающая длину массива

#Пример 1. Непонятный PERL
sub count; # объявление функции
$x = count(1,2,30) # Вызов функции. Передаётся список (массив) из трёх чисел
print "L = $x\n";  #L = 3
sub count
{ @_;}
__END__
Более понятно функция записывается так:
sub count
{  my @a = @_;
   $L = @a;
}

Для принудительного выхода из подпрограммы служит оператор return.

Синтаксис оператора return

  return
или
  return выражение 
Функция возврщает значение выражения 

Пример возврата значения оператором return

print koren(-2),"\n"; #печатается "корень мнимый"
print koren(4),"\n"; #печатается 2
sub koren
{  my($x) = @_;
   if($x < 0) { return "корень мнимый"}
   else       { return $x**0.5;}
}

Пример возврата массива (списочный контекст)

$d1=1; #признак нечётных дней недели
@DN=chetNechet($d1);
foreach (@DN) {print "$_\n";}
sub chetNechet
{  my($n) =@_;
   if($n == 1) {qw(пон среда пят);}
   else        {qw(вт чет суб);}
}
__END__
Результат
пон  
среда 
пят

Жёсткие и символические ссылки

Жёсткие ссылки

Жёсткая ссылка на переменную - это адрес пременной. Жёстким ссылкам соответствуют указатели на языке "С".

Над жёсткой ссылкой выполняются две операции : присвоение ей адреса переменной и получение по ссылке значения переменной (разыменовывание).

Операция присвоения ссылке адреса переменной

  ссылка = \имя_переменной;
например
  $gs = \$a;

Операция разыменовывания состоит в добавлении разыменовывающего символа ($, @, %) перед именем ссылки

Примеры операции разыменовывания ссылки

$a=33;
$gs = \$a;
#разыменовывание
$c = $$gs; #$c = $a = 33
@b = qw(a b c);
$gs = \@b;
#разыменовывание
@c = @$gs; #@c копия массива @b

Примеры использования жёстких ссылок

$a=5;
@b=(2,4,6); 
$gs=\$a;                 # Жёсткая ссылка на $a
print $$gs," \$gs=$gs\n"; 
#Напечатается 5 $gs=SCALAR(0x32de9c)
$gs=\@b;                  #Жёсткая cсылка на массив
print @$gs[1],"\n"; # 4
@f=(1,2,3);
#Ввести чёт (ch) нечет (любой символ)
$x=<>;
print "x=$x\n";
if($x eq "ch\n"){$gs=\@b} # Жёсткая cсылка на массив @b
else            {$gs=\@f} # Жёсткая cсылка на массив @f
foreach $a (@$gs){print "$a \n";} #Печать массива в столбик
__END__
Результат
5 $gs=SCALAR(0x228de9c)
4
x=ch

2 
4 
6 

Символические ссылки

Символические ссылки хранят в себе не адрес переменной, а идентификатор.

Пример символической ссылки

$z = 5;
$simv = 'z';
print "$$smv $simv\n"; # 5  z

В примере переменная $simv одновременно является и обычной переменной, имеющей значение 'z', и ссылкой на переменную $z. Напомним, что имя переменной состоит из разыменовывающего символа ($, @, %) и идентификатора. В прикладных программах сиволические ссылки применяются очень редко. Рассмотрим забавный пример.

Пример использования символической ссылки.

$XVI="Иван Васильевич";
$XVIII="Пётр Алексеевич";
$XIX="Николай Павлович";
$vek=<>; # ввести век римскими цифрами, например, XVI
chomp($vek);
#Если $vek="XIX", то $$vek - ccылка на переменную $XIX
print "В $vek веке царствовал $$vek\n";
#В XIX веке царствовал Николай Павлович

Символические ссылки - потенциальный источник ошибок, поэтому в Perl есть специальная прагма strict "refs", запрещающая символические ссылки.

Жесткие ссылки и двумерные массивы

Рассмотрим пример печати двумерного массива

$ref1 = [3,4 5]; #ссылка на анонимный массив
@D = ( [qw(a b)],
       $ref1,
      [1,2,3]);
foreach $ref (@D)
{  foreach (@$ref)
   {  print "$_ ";}
   print "\n";
}
__END__
Результат
a b 
3 4 5 
1 2 3 

В примере двумерный массив @D рассматривается как одномерный массив ссылок на анонимные массивы. Массив, одномерный или двумерный, можно передавать в функцию по имени, если в списке фактических параметров только один массив и стоит он последним после всех скаляров. Во всех других случаях нужно передавать массивы по сылке.

Пример передачи скаляра и ссылки на двумерный массив

F_mas2Ref(34,\@D);
sub F_mas2Ref
{my($a,$f)=@_;
  print "a=$a ",$f->[1][2],"\n"; #Печатается а=34 5
}

Создание собственного модуля

Задача. Создать модуль, содержащий две функции и две переменные.

Файл модуля должен иметь расширение .pm. Транслятор Perl ищет модули в каталогах, указанных в специальном массиве @INC. Распечатаем массив @INC:

foreach (@INC){print "$_\n";
__END__
Результат примерно такой
C:/WebServer/usr/lib
C:/WebServer/usr/site/lib

Создадим каким-либо текстовым редактором файл и сохраним его под именем MyModul.pm в одном из каталогов, указанных в @INC.

Текст модуля MyModul.pm

=head1 NAME
Пример модуля
Модуль содержит 3 переменных и две функции
Функция soob распечатывает пути к библиотекам 

=cut

package MyModul;
require Exporter;             #для экспорта имён из MyModul
our @ISA=qw(Exporter);        #Массив @ISA содержит имена пакетов,
                              #в которых нужно искать вызываемый метод,
                              #если она отсутствует в текущем пакете
our @EXPORT=qw(soob $beta);   #список имён, экспортируемых по умолчанию
our @EXPORT_OK=qw($alfa sum_);#список имён, экспортируемых
                              #при явном указании 
our %EXPORT_TAGS=( func=>[qw(soob sum_)],
                   perem=>[qw($alfa $beta)],
                   vse=>[qw(soob sum_ $alfa $beta)]
                 );
our $VERSION=1.0;
#**** Переменные ****
$alfa="Я здесь явно";
$beta="По умолчанию";
$gamma="Я квалиф.";
# ***** Функции *****
sub soob
{  print "Мой модуль работает\n";
   print "Объект ISA=@ISA\n";
}
sub sum_
{  $s=0;
   foreach (@_){$s+=$_;}
   return $s;
}
1;

Модуль должен заканчиваться строкой 1;.

Стандартный модуль должен содержать в себе документацию. В MyModul.pm документация находится между директивами =head1 и =cut.

Первым оператором package MyModul; весь модуль превращается в пакет с именем MyModul. Вне пакета к его глбальным переменным нужно обращаться по квалифицированному имени, например, $MyModul::alfa. Принято давать одинаковые имена модулю, файлу и пакету.

Массивы @EXPORT, @EXPORT_OK и хеш %EXPORT_TAGS специальные. Для их обработки при трансляции используются специальные методы. Траслятор, не найдя нужные методы в MyModul, просматривает пакеты из @ISA. Там, в нашем случае, один пакет Exxporter, в котором нужные методы и находятся.

Способы загрузки модуля

a) use MyModul; #Экспортируются soob() и $beta, указанные в @EXPORT
   
б) use MyModul qw(sum_ $alfa);
  #Экспортируются sum_() и $alfa, указанные в @EXPORT_OK 
  
в) use MyModul qw(sum_);  #Экспортируются sum_()

г)  use MyModul qw(sum_ soob()  $beta );  
    #Экспортируются sum_(), soob() и $beta

д) use MyModul qw(:vse);
   #Экспортируются sum_(), soob(), $alfa и $beta,
   #указанные в элементе $EXPORT_TAGS{"vse"} 

Пример скрипта, использующего MyModul

=c
Доступны только явно перечисленные имена
из массивов @EXPORT и @EXPORT_OK
=cut
use MyModul qw(sum_ $alfa);
$sum=sum_(1..5);
print "sum=$sum\n";
print "alfa=$alfa. beta=$beta gamma=$MyModul::gamma\n";
__END__
********** Р Е З У Л Ь Т А Т Ы *********
sum=15
alfa=Я здесь явно. beta= gamma=Я квалиф.

Библиотека модулей LWP

LWP (сокращение от "Library for WWW in Perl") - это группа модулей для обмена данными в Intеrnet. Используя эти модули, принципиально можно на Perl написать браузер. Пользуясь различными модулями из LWP, можно решать задачи передачи данных методом POST, доступа к данным через прокси-сервер, доступа к защищенным документам и файлам COOKIE, работать по протоколу HTTPS и т.д. Описаное всех модулей LWP занимает очень большой объём, поэтому рассмотрим простой, но важный модуль LWP::Simple.

Модуль LWP::Simple содержит функции для чтения HTML-документов. Для поиска документа используется его URL. Синтаксис функций очевиден, поэтому сразу рассмотрим примеры.

use LWP::Simple;
$URL="http://i.voenmeh.ru";

#функция get() - чтение документа в строковую переменную
$document = get($URL);
print $document;
#Можно получать и генерируемые скриптами HTML-документы
$document = getprint("http://www.kafi5.loc/kam.loc/PrimPHP/display.php?name=%CC%E0%F8%E0&age=5");
#%CC%E0%F8%E0 - Маша

#функция getstore() - чтение и запоминание документа в файл
getstore($URL,$file);

#функция getprint() - чтение и печать документа
$document = getprint($URL);

#функция head() - получение заголовков докумета 
($content_type, $document_length, $modified_time, $expires, $server) 
= head("http://i.voenmeh.ru");

Графическая библиотека GD

Графическая библиотека GD служит для построения или загрузки изображений. В библиотеке есть методы построения прямых линий, дуг, эллипсов, многоугольников, вставки в изображение надписей. Можно строить или изменять изображение с точностью до одного пикселя.

Пример

#!\usr\bin\perl
=с
ПОСТРОЕНИЕ МНОГОУГОЛЬНИКА С ЗАДАННЫМ ЧИСЛОМ СТОРОН
Последовательность действий:
 - принимается поступившее из браузера число сторон n,
 - строится изображение правильного n-угольника,
 - изображение сохраняется в файле в PNG-формате,
 - формируется HTML-документ для вывода в окно браузера 
    сохранённого в файле изображения
=cut
use GD;
use CGI qw(:param);
print "Content-type: text/html\n\n";
$n=param("n"); # n - заданное пользователем число сторон
$im =  GD::Image::-> new(200,200); #  Два способа
#$im =  new GD::Image(200,200);    #  создания объекта
$red = $im->colorAllocate(255,200,220); #задаётся цвет фона
$blue = $im->colorAllocate(0,0,255);
# Построение полигона
$poly = new GD::Polygon; #создаётся объект "многоугольник"
$pi=3.14159;
$fi=2*$pi/$n;
for ($i=0;$i<$n;$i++)
{  $psi= ($i)*$fi-$pi/2;
   $x=sprintf("%4.0f",(cos($psi)+1)*40)+60;
   $y=sprintf("%4.0f",(sin($psi)+1)*40)+60;
   $poly->addPt($x,$y); # добавить вершину многоугольника
}
$im->filledPolygon($poly,$blue);
$Fn="poli.png";
chdir '..\www\Kam.loc';
open(PFIL,">$Fn");
#установка чтения-записи двоичного файла
 binmode PFIL;
# ВЫВОД ИЗОБРАЖЕНИЯ В ФАЙЛ
 print PFIL $im->png;
# ФОРМИРОВАНИЕ HTML-документа
 print "<html><HEAD><TiTLE>Многоугольники</title>"
 ."<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE\"></head>"
 ."<BODY><H1 align=\"center\">"
 ."<font color=#700000 >МНОГОУГОЛЬНИК</font></H1>"
 ."<DIV align=\"center\"><IMG SRC=http:../Kam.loc/$Fn ></div>"
."</body></html>\n";

Результат выполнения примера при n=5 приведён на рис. 1.

Рис. 1. Многоугольник

Документирование на языке POD

Модули Perl обязательно содержат в себе полное описание (руководство пользователя). Для описания создан специальный язык POD (Plain Old Documetation - простая старая документация). Можно сказать, что модуль состоит из перемежающихся фрагментов текста на языках Perl и POD Транслятор Perl выбрасывает все фрагменты текста, написанные на POD, а трансляторы POD только эти фрагменты и учитывают.

POD - язык разметки текста, напоминающий HTML, но с гораздо меньшими возможностями. Сделано это специально. В ставшей классической монографии Программирование на Perl Ларри Уолл с иронией пишет: "Заставить программистов писать документацию почти так же сложно, как носить галстук. POD был задуман таким простым, чтобы даже программист мог (и стал) на нём писать."

Для задания способов разметки в POD служат директивы, играющие ту же роль, что и теги в HTML. Все директивы POD должны начинаться с символа "=" в первой позиции строки.

Директивы POD

Заголовки

=head1
=head2
. . .

Конец фрагмента текста

=cut

Указание транслятору, что анализ участка должен быть отложен до следующей директивы =cut

=pod

Начало и конец списка

=over NUMBER
=back
  где NUMBER - число пробелов в отступе (необязательный параметр)

Элемент списка

=item SYMBOL
  где SYMBOL - номер или маркер 

Директивы, указывающие транслятор, для которого предназначен данный фрагмент

=for TRANSLATOR
=begin TRANSLATOR
=end TRANSLATOR

Трансляторы POD называют форматерами. Форматер html выводит документацию в виде HTML-документа, форматер text - в виде тестового файла.Имеется большое количество форматеров, но ни один форматер не воспринимает названия comment. Можно использовать comment для многострочных комментариев, не относящихся к документации. Директивы =for, =begin и =end ограничивают фрагмент предназначенный только для указанного транслятора

Прмер части скрипта masRef.pl c разметкой на языке POD

=head1 NAME

ARRAY

    Примеры передачи в подпрограммы массивов
Рассматривается передача массивов: 

=over 2

=item 1
по ссылке

=item 2
по имени

=item 3
вместе со скалярами

=back 

Рассматривается изменение фактических
параметров через семантическую связь по ссылке

=cut
@a=(1,2,3,4,9);    # создание массива
@b=(5,6,7,8);
$ref_b=\@b;
 . . . . . .
 . . . . . .

Команда для формирования текстового файла с документацией скрипта masRef.pl:

C:\perl\bin\pod2Text perl\web_pl\masRef.pl > perl\web_pl\masRef.txt

Этой командой вызывается текстовый форматер POD

Содержимое файла masRef.txt

ARRAY
        Примеры передачи в подпрограммы массивов
Рассматривается передача массивов:
    1 по ссылке
    2 по имени
    3 вместе со скалярами

    Рассматривается изменение фактических параметров через семантическую
    связь по ссылке

Команда для формирования HTML-файла с документацией скрипта masRef.pl:

C:\perl\bin\pod2HTML --title=title perl\web_pl\masRef.pl > perl\web_pl\masRef.HTML
c:\Perl\bin>pod2Text.bat C:/perl/site/lib/MyModul.pm >C:/perl/WEB_PL/MyModul.txt