Подпрограммы - Язык программирования PERL. Сфера применения

Как и все структурированные языки программирования, Perl поддерживает подпрограммы. Подпрограмма может быть определена с помощью ключевого слова sub, как показано ниже:

sub demo_sub

{

print "demo_sub called ";

}

&demo_sub; # вызов подпрограммы

В данном случае инструкции образуют подпрограмму, названную demo_sub. Для вызова подпрограммы скрипт помещает знак амперсанда (&;) перед именем подпрограммы. При вызове подпрограммы в языке Perl скобки могут быть опущены. Вы можете разместить подпрограмму где угодно в пределах исходного кода скрипта, потому что Perl проанализирует весь исходный текст перед тем, как начать выполнение скрипта. Можно объявить подпрограмму в исходном коде сразу после первого использования подпрограммы (forward reference). Подпрограммы могут иметь аргументы и возвращать значения. Следующий фрагмент кода содержит подпрограмму с именем show_value, которая выводит значение, полученное подпрограммой в качестве параметра:

sub show_value

{

print 'The value id ', $_[0];

}

&;show_value(1001);

Формально подпрограмма языка Perl не объявляет переменных для хранения аргументов. Вместо этого в подпрограмму передается переменная типа массив с именем @_, которая содержит значения параметров. В свою очередь, подпрограмма получает доступ к значениям аргументов, используя следующие обозначения для элементов массива: $_[0], $_[1], и т. д. Однако такой способ передачи параметров может ухудшать читаемость кода, и поэтому большинство подпрограмм используют копирование аргументов в локальные переменные. Аналогично предыдущему примеру, следующая подпрограмма show_fwo_values выводит значения двух параметров:

sub show_two_values

{

print 'Первый параметр ', $_[0], " ";

print 'Второй параметр ', $_[0], " ";

}

&;show_two_values(1001, 2002);

Наконец, следующая функция show_all_values выводит значения всех параметров, которые она получает. Функция использует массив для определения числа параметром:

sub show_all_values

{

for ($i = 0; $i < @_; $i++)

{

print 'Parametr ', $i, ' is ', $_[$i], " ";

}

}

&; show_all_values(1001, 2002, 3003, 4004);

Как было сказано, подпрограммы Perl могут возвращать значения. Для этого используется инструкция return. В противоположность языку С, Perl не требует обязательного использования инструкции return. Если подпрограмма не содержит инструкцию return, то в качестве возвращаемого значения будет взято последнее оцененное выражение. В следующем примере складываются два параметра и возвращается результат:

sub add_values

{

return $_[0] + $_[1];

}

print 'The result is: ', &;add_values(1001, 2002);

Библиотека подпрограмм

В противоположность языку С, Perl фактически не поддерживает концепцию библиотеки. Тем не менее, в нем имеется механизм, позволяющий скриптам использовать исходный код из другого файла. Например, предположим, что вы храните подпрограмму add_valuesl вфайле под именем addvalue. pl. Используя инструкцию require, другой скрипт на языке Perl может получить доступ к той подпрограмме, как показано ниже:

require "addvalue. pl";

print &;add_values(10, 11);

Вы можете представлять себе инструкцию require как аналогоператора #include препроцессора языка С. Чтобы найти файл исходных кодов, Perl сначала ищет в каталоге, определенном по умолчанию для библиотеки языка Perl (подробности можно уточнить в инструкции по инсталляции), а затем в текущем каталоге. Можно также использовать абсолютный или относительный путь, к которому добавлено имя файла. Perl запоминает, какие файлы были затребованы оператором require, и загружает их только один раз даже в случае многочисленных обращений к этим файлам. Имеется много стандартных библиотек, которые расширяют возможности языка Perl. Сейчас самое время побродить по каталогу, в котором хранятся библиотечные файлы языка Perl, чтобы получить представление о тех возможностях, которые они предлагают.

Использование пакетов для изоляции подпрограмм

Если у вас имеется много подпрограмм, особенно подпрограмм, которые вы храните в различных файлах, то может возникнуть коллизия имен переменных, когда одно и то же имя переменной используется в различных целях. Perl помогает избежать этого с помощью пакетов (packages). Как известно, объявляя локальные переменные для подпрограмм, можно избежать коллизии имен. Однако если несколько подпрограмм совместно используют какие-то специфические данные, то эти данные могут потребовать глобальной области видимости, что как раз и может вести к коллизии имен. Используя пакеты, можно группировать глобальные данные в частные пространства имен (name-spaces), вне пределов которых глобальные переменные не видны, т. е. неизвестны. Рассмотрим приведенный ниже простой пример, в котором две подпрограммы (находящиеся в различных файлах) используют частные, индивидуальные пространства имен.

# Код в файле one. pl

sub sub_one

{

package demo_one;

$some_data = 10;

}

# * * * * * * * *

# Код в файле two. pl

sub sub_one

{

package demo_two;

$some_data = 20;

}

Как можно видеть, первая подпрограмма использует имя пакета demo_one, вторая подпрограмма использует имя пакета demo_two. Обе подпрограммы могут устанавливать и использовать переменную $some_data без возникновения коллизии имен между одной и другой глобальными переменными. Скрипт <знает> имя пакета, в пределах которого находится переменная, и он организует доступ к ней, использует имя пакета в качестве префикса к имени переменной. В следующем примере имя пакета package_one или package_two добавляется в качестве префикса к имени переменной some_data:

&sub_one;

&sub_two;

print "Переменная 1 $package_one'some_data "

print "Переменная 2 $package_two'some_data "

Когда вы используете пакеты языка Perl, можете создать уникальное пространство имен в пределах текущего файла исходных кодов путем помещения инструкции package в начале файла, как показано ниже:

package some_package_name

$some_data = 1;

sub some_sub

{

return $some_data;

}

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

require 'some_package. pl';

print &;some_package_name'some_sub;

Обработка строк

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

Функция CHOP

Функция chop удаляет последний символ строки. Она имеет следующий формат:

$character = chop(Str);

Функция chop возвращает удаленный символ. Скрипты языка Perl широко используют chop для удаления символа перехода на новую строку и символа конца строки.

Функция INDEX

Функция index осуществляет поиск заданной подстроки в строке. Она имеет следующий формат:

$location = index(Str, SubStr[, Offset]);

Функция index возвращает индекс первого вхождения подстроки(SubStr) в строку (Str). Факультативно может быть задан сдвиг от начала (Offset), после которого начинается поиск. Если подстрока не найдена, возвращается значение -1. В следующем примере функция index ищет вхождения подстроки 'па' после третьего символа в строке 'banana':

print index('banana', 'na', 3); # Выведет 4.

Функция RINDEX

Функция rindex ищет последнее, самое правое вхождение подстроки в строку и возвращает значение позиции первого символа подстроки. Функция имеет следующий формат:

$location = rindex(Str, SubStr);

Эта функция аналогична функции index, за исключением того, что она возвращает последнее вхождение, а не первое. Например, в следующем примере функция rindex используется для определения последнего вхождения подстроки 'na' в строку 'banana':

print rindex('banana', 'na'); # Выведет 4

Функция LENGTH

Функция length возвращает число символов в строке. Она имеетследующий формат:

$len = length(Str);

В следующем примере функция length используется для вывода числа символов в строке:

print length('banana'); # Выведет 6

Функция SUBSTR

Функция substr используется для удаления части строки. Она имеет следующий формат:

$substring = substr(Str, Offset[, Len]);

Функция возвращает подстроку, т. е. часть строки, длина которой не превышает величины, заданной факультативным параметром Len. Возвращаемая подстрока строки str начинается с символа в позиции, заданной сдвигом Offset. Если параметр Len опущен, то возвращаемая строка содержит символы до конца строки включительно. Если параметр Offset отрицательный, то сдвиг вычисляется от конца строки. Наконец, скрипт может использовать substr как lvalue для выполнения операции присваивания. Следующий фрагмент кода иллюстрирует использование функции substr.

print substr('orange', 3); #Выведет 'nge'

print substr('orange', -2); # Выведет 'ge'

print substr('orange', 2, 2); # Выведет 'an'

$str = 'apple';

substr($str, -3) = 'ricot';

print $str; # Выведет 'apricot'

Примечание: Часто использование операторов языка Perl для регулярных выражений оказывается более эффективным, чем функции substr. Регулярные выражения обсуждаются ниже в данной главе.

Функция JOIN

Функция join соединяет список элементов в строку, разделяя каждый элемент заданным символом. Она имеет следующий формат:

$new_string = join(Str, List);

Функция join конвертирует каждый элемент списка в строку и соединяет строки. Следующий фрагмент кода иллюстрирует использование функции join:

$str = join(', ', 0. . 4, 10, 20); # Список будет '0, 1, 2, 3, 4, 10, 20'

$strn = join (" ", $a, $b, $c);# Смешает списки

Функция SPLIT

Функция split разделяет содержимое строки на список элементов. Она имеет следующий формат:

split(Delimeter, Str[, Limit]);

Аргумент Delimeter определяет символ, по которому осуществляется разделение, например, пробел, слово, символ табуляции ит. д. Факультативный параметр Limit задает максимальное число элементов, которое может содержать список. Следующий пример иллюстрирует использование функции split.

Функции для обработки списков

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

Функция REVERSE

Функция reverse реверсирует элементы списка. Она имеет следующий формат:

@new_list = reverse(@List);

Функция reverse реверсирует список и возвращает новый результирующий список. Следующий пример иллюстрирует использование функции reverse:

@list = reverse(1. . 5); # Результат 5, 4, 3, 2, 1

@list = reverse(@list); # Результат 1, 2, 3, 4, 5

Функция SORT

Функция sort сортирует элементы списка. Она имеет следующий формат:

@new_list = sort(@List);

Или

@new_list = sort(Subroutine @List);

Или

@new_list = sort(BlockStatement @List);

Функция sort размещает элементы в списке, упорядочивая их в соответствии с порядковыми номерами символов в таблице ASCII-кодов. Так же как и функция reverse, функция sort возвращает в качестве значения новый список и не воздействует на исходный список. Следующий пример иллюстрирует использование функции sort:

@list = sort (1, 5, 2, 3, 4); # Результат 1, 2, 3, 4, 5

@list = sort(1, 2, 10); # 1, 10, 2 сортировка в ASCII

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

@list = sort({$a <=> $b} (2, 1, 10)); # @list 1, 2, 10

@list = sort({$b <=> $a}) (2, 1, 10); # @list 10, 2, 1

sub mycomp

{

$b <=> $a

}

@list = sort(mycomp (2, 1, 10)); # @list 10, 2, 1

Функции работы с массивами

Как известно, массив представляет собой структуру данных, содержащую одно или несколько значений величин одного типа, например, 100 имен студентов. Perl содержит несколько встроенных функций, которые помогают работать с элементами массива. В следующих разделах рассматривается несколько основных функций для обработки массивов.

Функции PUSH И POP

Скрипты языка Perl используют фикции push и pop для того, чтобы добавлять и удалять элементы с конца массива. Иными словами, функции push и pop позволяют скриптам выполнять операции со стеком по принципу: последним вошел, первым вышел. Функция push имеет следующий формат:

push(@ARRAY, LIST);

Следующий фрагмент иллюстрирует использование функции push:

@list = ();

push(@list, 10, 20); # @list теперь (10, 20)

push(@list, 1. . 3); # @list теперь (10, 20, 1, 2, 3)

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

$value = pop(@ARRAY);

Следующий фрагмент программы иллюстрирует использование функции pop:

# Возьмем @list из предыдущего примера

print pop(@list); # Выведет 3

print pop(@list); # Выведет 2

# Теперь @list (10, 20)

Функция SHIFT

Функция shift удаляет и возвращает элемент из начала массива. Эта функция аналогична функции pop с тем только отличием, что работает от начала массива по принципу FIFO (<первым вошел, первым вышел>). Функция shift имеет следующий формат:

$value = shift(@ARRAY);

Следующий фрагмент программы иллюстрирует использование функции shift:

# Возьмем @list из предыдущего примера

print shift(@list); # Выведет 10

print shift(@list); # Выведет 20

# Теперь @list ()

Функция UNSHIFT

Функция unshift добавляет один или больше элементов к началу массива. Она имеет следующий код:

unshift(@Array, List);

Следующий фрагмент программы иллюстрирует использование функции unshift:

# @list = ()

unshift(@list, 5, 10, 20); # @list (5, 10, 20)

unshift(@list, 1. . 3); # @list (1, 2, 3, 5, 10, 20)

Функция SPLICE

Скрипты языка Perl используют функцию splice для того, чтобы извлекать элементы из списка, заменяя их элементами другого списка. Она имеет следующий формат:

splice(@Array, Offset[, Count[, List]]);

Функция splice извлекает указанное число элементов {Count) из массива (@Аrraу), начиная с элемента, на который указывает величина сдвига (Offset), и заменяет элементы элементами другого списка (List). Если в вызове функции не указан параметр Count, функция извлекает элементы до самого конца массива. Если в вызове функции не указан список, элементами которого замещаются исходные элементы, то функция не добавляет никаких элементов к первоначальному списку. Следующее выражение иллюстрирует использование функции splice:

@list = 1. . 10;

splice(@list, 1, 8, 5, 6); # @list = (1, 5, 6, 10)

Функция SCALAR

Функция scalar определяет число элементов в списке. Она имеет следующий формат:

Rsult = scalar(List);

Обычно скрипты языка Perl не нуждаются в использовании функции scalar применительно к массивам, потому что когда скрипт обращается к массиву, записывая его в скалярном контексте, то он получает в качестве возвращаемой величины число элементов массива. Тем не менее, скрипты могут использовать функцию scalar в случаях, когда контекст является неоднозначным или если список не является массивом. Следующее выражение иллюстрирует использование функции scalar.

@list = 1. . 10;

print scalar(@list); # Выведет размер @list

ФУНКЦИЯ GREP

Функция grep фильтрует элементы списка, для которых заданное выражение принимает значение <ложно>. Она имеет следующий формат:

@list = grep(Expression, List);

Функция grep просматривает элементы списка, подставляя их в качестве аргумента в заданное выражение. Функция grep присваивает текущее выражение элемента списка переменной $_ и вычисляет заданное выражение. Если полученное выражение является истинным, то функция grep добавляет этот элемент к результирующему списку. Следующий фрагмент программы иллюстрирует использование функции grep:

@list = grep($_ &; 1, 1. . 10); # @list (1, 3, 5, 7, 9)

@list = ('a', '' 'b'); # @list ('a', ' ', 'b')

@list = grep($_ eq '', @list); # @list ('a', 'b')

Примечание: Если выражение, модифицирует переменную. $_, то исходный список также будет модифицирован.

Функции обработки ассоциативных массивов

Как известно, ассоциативные массивы - это такие массивы, у которых индексом является не числовая величина, а, например, имя. В языке Perl имеется несколько встроенных функций, которые упрощают обработку скриптами ассоциативных массивов.

Функция KEYS

Функция keys возвращает значения ключей, которые отвечают ассоциативному массиву. Она имеет следующий формат:

@key_list = keys(%Array);

Функция keys возвращает массив ключей в виде регулярного списка. Следующий фрагмент программы иллюстрирует использование функции keys:

$ages{'Bob'} = 25;

$ages{'Mary'} = 30;

$ages{'Zack'} = 15;

@list = keys(%ages); # @list будет 'Zack', 'Bob', 'Mary'

@list = sort keys %ages # @ list 'Bob', 'Mary', 'Zack'

for $key (sort keys %ages)

{

print "$key is $ages{$key} "

}

Функция VALUES

Функция values возвращает обычный массив, состоящий из значений ассоциативного массива. Она имеет следующий формат:

@value_list = values(%Array)

Функция values возвращает массив значений ассоциативного массива в виде регулярного списка. Следующий фрагмент программы иллюстрирует использование функции values:

# Используем значения из предыдущего примера

%ages = ('Bob', 25, 'Mary', 30, 'Zack', 15);

@list = sort values %ages; # @list (15, 25, 30)

@list = %ages; # @list ('Zack', 15, 'Bob', 25, 'Mary', 30)

Функция EACH

Функция each осуществляет итерации элементов в ассоциативном массиве. Она имеет следующий формат:

@key_values = each(%Array);

Всякий раз, когда скрипт вызывает функцию each, она возвращает список из двух компонент, которые содержат пару ключ-значение. Когда функция достигает конца списка, она возвращает пустой список. При следующем вызове функции процесс итерации начнется сначала. Следующий фрагмент программы иллюстрирует использованиефункции each:

# Используем значения из предыдущего примера

%ages = ('Bob', 25, 'Mary', 30, 'Zack', 15);

While (($name, $age) = each %ages)

{

# Выведем ages

print "$key is $ages{$key} ";

}

Функция DELETE

Функция delete удаляет элементы ассоциативного массива. Онаимеет следующий формат:

Delete $Array{Key}

Следующая инструкция использует функцию delete для того, чтобы удалить элемент, отвечающий ключу Bob из ассоциативногомассива $Employees:

Delete $Employees{'Bob'}

Аргументы командной строки

Скриптам на языке Perl легко получить доступ к аргументам командной строки. Всякий раз, когда запускается скрипт, Perl помещает аргументы командной строки скрипта в списочную переменную@ARGV. Следующий фрагмент программы служит для вывода аргументов командной строки на дисплей:

while ($arg = shift @ARGV)

{

print "$arg ";

}

Доступ к переменным окружения

Доступ к переменным окружения осуществляется в скриптах на языке Perl также очень просто. Всякий раз при запуске скрипта Perl помещает копии переменных окружения в ассоциативный массив с именем %ENV. В следующей инструкции массив %ENV используется для вывода текущего каталога:

print "$ENV{PATH} "; # Выведет текущий каталог

Кроме получения значений из массива %ENV, скрипты также могут изменять элементы массива. Такие изменения массива %ENV изменят установку переменных окружения для всякого процесса-потомка, создаваемого скриптом. Например, следующая инструкция использует массив %ENV для изменения текущего пути:

$ENV{PATH} = 'c:myexec;'. $ENV{PATH};

Примечание: Изменения, которые скрипт делает в массиве %ENV, не повлияют на исходные переменные окружения. Иными словами, после окончания работы скрипта переменные окружения системы не изменятся.

Файловый ввод и вывод

Perl специально разрабатывался для того, чтобы служить адекватным средством для чтения и записи в текстовые файлы. Тем не менее, как вы узнаете далее, Perl выполняет функции по произвольному доступу и вводу-выводу бинарных файлов. Операции по работе с файлами требуют указатель файла (file handle), который является переменной, соответствующей конкретному файлу. По умолчанию каждый скрипт на языке Perl имеет три стандартных указателя, которые Perl автоматически открывает при запуске скрипта: STDJN, STDOUT, STDERR. Эти три стандартных указателя отвечают стандартным потокам STDIN, STDOUT, STDERR языка программирования С. Кроме того, скрипт языка Perl может открыть дополнительные указатели для других специфических файлов.

Открытие файлов и других потоков

Для того чтобы скрипт использовал файл, он должен вызвать функцию open. Она имеет следующий вид:

open(FileHandle[, FileName])

В отличие от функции open библиотеки времени выполнения языка С, функция open языка Perl не содержит параметра mode в вызове функции. Perl определяет режим (mode) открытия файла, основываясь на имени файла. Таблица 12. 3 иллюстрирует связь режима открытия файла и имени файла.

Табл. 12.3. Соглашение об именах и режимах доступа файлов языка Perl

Имя файла

Операция

<FILE>

Открыть файл только для чтения (аналогично <r> функции fopen)

<<FILE>

Открыть файл для чтения (то же самое, что <FILE>)

<>FILE>

Создать файл для записи (как <w> функции fopen

<>>FILE>

Открыть файл для добавления в его конец (как <г+> функции fopen)

<+>FILE>

Создать файл для чтения/записи (как <rw> функции fopen)

<+<FILE>

Открыть файл для чтения/записи (как <rw+> функции fopen)

<| CMD>

Открыть канал из процесса, исполняющего оманду <CMD>

<CMD |>

Открыть канал процессу, исполняющему команду <CMD>

Примечание: Режим канального (pipe) потока может существовать не
На всех системах.

Если в вызове функции open опущено имя файла, то Perl подразумевает, что имя файла содержится в строковой переменной $FileHandle. Когда скрипт завершил использование файла, он закрывает его, используя функцию close, как показано ниже:

close(FileHandle);

Фрагмент программы иллюстрирует использование функций open и close:

open(InFile, "test. dat") || die; # открываем для чтения

# test. dat

open(OutFile, ">test. dat") || die; # создаем test. dat

$AuxFile = ">>test. dat";

open(Aux, $AuxFile) || die; # открывает для дополнения

# test. dat

close(InFile);

close(OutFile);

close(Aux);

Обратите внимание, что указатели файлов не имеют обычных одно символьных префиксов. Как вы узнаете далее, скрипты языка Perl могут хранить имена указателей в виде строк скалярных переменных и передавать указатель любой функции, которая может их обрабатывать. При необходимости Perl выполняет конвертацию значений. В операционной системе MS-DOS Perl поддерживает дополнительную функцию, которая называется hinmode и позволяет файловому вводу/выводу переключаться между текстовым и бинарным режимами. В большинстве же систем различие между текстовым и бинарным режимами не имеет значения. Однако для операционной системы MS-DOS символ новой строки представляет собой последовательность из двух символов (CR+LF). Поскольку большинство программ не ожидают встретить два символа в конце строки, то система ввода/вывода должна выполнить преобразование. Для того чтобы можно было использовать функцию binmode, соответствующий указатель может быть открыт. Функция binmode имеет следующий формат:

binmode(FileHandle);

Построчное чтение и запись данных

Простейшим способом для чтения скриптом строки из файла служит использование оператора <FILEHANDLE'>. В языке Perl указатель файла, окруженный треугольными скобками, становится символом ввода (input-symbol). Например, следующий фрагмент программы иллюстрирует использование символа ввода для чтения и вывода на экран содержимого файла Test. dat.

open(InFile, "Test. dat") || die;

while ($line = <InFile>)

{

print $line; # Выведет строку из файла

}

close(InFile);

Когда символ ввода достигает конца файла, он возвращает значение false, которое в данном случае заканчивает выполнение цикла while. Существует специальный (пустой) символ ввода, обозначаемый <>, который имеет весьма специальное, но полезное применение. В первый раз, когда скрипт использует пустой символ ввода<>, он анализирует аргументы командной строки. Если строка @ARGV является пустой, то входной символ <> читает из STDIN. Если вместо того @ARGV не пуста, то Perl открывает первый из файлов, указанных в переменной @ARGV, и читает содержимое файла. Когда Perl заканчивает обработку одного файла, он приступает к следующему. После того как скрипт прочитал все файлы, символ <> возвращает значение false. Скрипты языка Perl также могут использовать символ ввода для чтения всего содержимого файла в массив так, что каждая строка файла становится элементом массива. Например, следующая инструкция читает из файла STDIN в массив @lines:

@lines = <STDIN>;

Запись данных в файл также достаточно проста. Фактически вы это делали всякий раз, когда использовали функцию print. Полный формат функции print имеет следующий вид:

Print [FileHandle] List;

Если функция print не получает в качестве аргумента указателя файла, то она посылает вывод в STDOUT. Следующий фрагмент программы иллюстрирует использование функции print для добавления данных в выходной файл:

open(LogFile, '>>logfile. dat') || die;

##############

($m, $d, $y) = (localtime(time)) [4, 3, 5];

print LogFile "Captain's log, Stardate ++m$/$d/$y ";

close(LogFile);

Примечание: Указатель файла и выходной список не разделяются запятой.

Чтение и запись блоков данных

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

$result = sysread(FileHandle, $Var, Length[, Offset]);

$result = syswrite(FileHandle, $Var, Length[, Offset]);

Если в вызове функций указывается сдвиг от начала файла(Offset), то функции выполнят поиск места, с которого они начнут операции ввода/вывода. Функции sysread и syswrite обе передают данные, используя скалярную переменную строкового типа. Поскольку функции обрабатывают фиксированные блоки памяти, то данные могут содержать бинарные значения, включая нули и маркеры конца файла. Если в вызове функции указывается сдвиг от начала файла (Offset), то функция выполняет поиск места в файле, с которого начинает выполнять операции ввода/вывода. Если вы работаете с блоками данных, то скрипты могут также использовать следующие функции ввода/вывода:

$result = seek(FileHandle, Position, Base);

$result = tell(FileHandle);

$result = eof(FileHandle);

Функция seek работает в точности так же, как fseek - функция библиотеки времени выполнения языка С. Параметр Position задает позицию относительно начала отсчета, которая в свою очередь задается параметром Base следующим образом:

? 0 Поиск от начала файлов

? 1 Поиск от текущей позиции

? 2 Поиск от конца файла

Функция tell языка Perl работает в точности так же, как фикция ftell библиотеки времени выполнения языка С. Эта функция возвращает текущую позицию в файле, с которой выполняются операции и чтения или записи. Наконец, функция eof, так же как и функция feof языка С, возвращает значение <истинно> или <ложино>, которое скрипт может использовать для определения достижения конца файла.

Обработка бинарных данных

Хотя Perl ориентирован в первую очередь на обработку текста, он также может обрабатывать бинарные данные. Скрипты могут перемещать бинарные данные частями, используя строковые переменные, и выполнять байтовые операции ввода/вывода, используя функции sysread и syswrite. Однако для того, чтобы выполнить что-нибудь<полезное> с данными, скрипт вынужден конвертировать данные в свои <родные> скалярные форматы.

Хранение бинарных данных

Когда скрипт на языке Perl читает блок бинарных данных, используя функцию sysread, он помещает эти бинарные данные в скалярную строковую переменную. Perl не заботится о том, что это заданные, содержат ли они нули или значения, не являющиеся ASCII-символами. В пределах символьной строки Perl принимает байты как байты. В отличие от языка С, Perl не использует строк, оканчивающихся нуль-символом. Если данные соответствуют кодовой таблице ASCII, то скрипт может их обрабатывать, как любой текст. Но если данные представляют собой бинарные величины, то скрипт обязан распаковать их перед тем, как Perl сможет обработать эти данные.

Распаковка строк бинарных данных в переменные языка PERL

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

$result = unpack(Template, Expression);

Expression является обычной строковой переменной, которая содержит бинарные данные, прочитанные функцией sysread, но может быть также выражением, которое необходимо интерпретировать как строку. Template представляет собой символьную строку-шаблон, описывающую, как интерпретировать значения в операнде Expression. Следующий фрагмент программы иллюстрирует использование функции unpack:

($r, $g, $b) = unpack("C3", $color);# распакует в 3 символа

@longwords = unpack("L*", $data); # распакует в список длинных # слов

@stuff = unpack("S2L", $bin); # распакует в 2 shorts и long

Каждый символ шаблона может сопровождаться числом, указывающим, сколько раз использовать этот символ. Если вместо числа стоит звездочка (*), то операция будет выполняться для всех остающихся данных в строке. Если число не поставлено, то она выполняется однократно. Скрипт может поместить любое число символов шаблона в строку Template. В таблице 12. 4 перечисляются символы, входящие в строковый параметр Template вместе с описанием влияния каждого из них на выполнение функции unpack.

Табл. 12. 4. Символы шаблона

Символ шаблона

Описание

A

Строка ASCII без нулевого символа

А

Строка ASCII без нулевого символа

B

Битовая строка (младший бит идетпервым)

В

Битовая строка (старший бит идет первым)

С

Однобайтовый символ со знаком

С

Однобайтовый символ без знака

D

Значение с плавающей запято, двойной точности

F

Значение с плавающей запятой, одинарной точности шаблона

H

Строка шестнадцатиричных значений (младшие разряды идут первыми)

Н

Строка шестнадцатиричных значений (старшие разряды идут первыми)

I

Целое со знаком

I

Целое без знака

L

Целое со знаком типа long

L

То же, только без знака

N

Короткое целое

N

Длинное целое

P

Указатель на строку

S

Короткое целое со знаком

S

Короткое целое без знака

U

Раскодировка строки

V

Короткое целое

V

Длинное целое

X

Пропустить вперед один байт

X

Пропустить назад один байт

@

Перейти на указанную позицию в строке

Упаковка данных в бинарные строки

Для вывода бинарных данных скрипт должен запаковать скалярные величины в строки бинарных символов. Для этого используется функция pack, формат которой указан ниже:

$result = pack(Template, List);

Следующий фрагмент программы иллюстрирует использование функции pack:

$color = pack("C3", $r, $g, $b);

$data = pack("L*", @longword);

$bin = pack("S2L", @stuff);

Функция pack использует те же самые символы шаблона, что и функция unpack, за исключением символов а. А, и, х, X, @.

Работа с каталогами

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

Открытие, чтение и закрытие каталогов

Скрипты на языке Perl позволяют открывать и читать содержимое файлов. Точно так же эти скрипты открывают каталоги и читают имена содержащихся в них слайдов. Для открытия каталога скрипты используют функцию opendir, передавая указатель каталога и путь к нему. Для чтения списка файлов, содержащихся в каталоге, скрипт использует функцию readdir. Наконец, для закрытия каталога используется функция closedir. Следующий фрагмент программы иллюстрирует использование функции readdir для того, чтобы вывести на экран список файлов в текущем каталоге:

opendir(Dir, $INC[2]) || die;

while ($file = readdir(Dir))

{

print "$file "

}

closedir(Dir);

В этом фрагменте используется переменная $INC[2J для доступа к текущему каталогу. Изменяя $INC[2] на $ARGV[0], скрипт выводит на экран список файлов, содержащихся в каталоге, который вы указали в командной строке. В дополнение к функциям для работы с каталогами, которые были рассмотрены выше, Perl предлагает еще набор фикций, которые позволяют позиционировать текущий указатель в списке каталога:

$result = rewinddir(DirHandle);

$result = telldir(DirHandle);

$result = seekdir(DirHandle, Position);

Форматированный вывод

В этой главе вы познакомились с несколькими способами форматирования выходных данных скрипта с помощью функции print. Аналогично языку С, Perl также поддерживает функции printf и sprintf. В дополнение Perl также поддерживает генерацию отчетов в форме столбцов, используя шаблоны форм.

Использование функции PRINT

В этой главе скрипты широко использовали функцию print. Кроме того, Perl обеспечивает специальные переменные, которые влияютна работу функции print. В таблице 12. 5 кратко характеризуютсяэти специальные переменные.

Табл. 12. 5. Специальные переменные, которые управляют функцией печати

Переменная

Назначение

$,

Разделитель для элементов печати

$"

Разделитель элементов списка при интерполяции строки

$

Разделитель для выходных записе

$#

Форматирование числового выхода (по умолчанию '%. 20g')

Для использования этих специальных переменных достаточнопросто присвоить им значения, которые вы хотите. Например, в следующем фрагменте программы используеся переменная $ для того, чтобы задать сепаратор между элементами печати:

$, = '*';

@list = 1. . 10;

print @list; # Выведет 1*2*3*4*5*6*7*8*9*10

Оказывается, что переменная $ на самом деле воздействует навсе строки, а не только на те, которые выводятся на печать. Однако чаще всего вы будете использовать ее для того, чтобы изменитьзначение, выводимое функцией print.

Форматированный вывод данных функцией PRINTF

Perl имеет функции printf и sprintf, которые очень похожи на соответствующие функции библиотеки времени выполнения языка С. Они имеют следующий формат:

$result = printf([FileHandle] Format, List);

$result = sprintf(Format, List);

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

$precision = 2;

$pi = 3. 1415;

printf("%. 2f ", $pi); # выведет 3. 14

printf("%. ${precision}f", $pi); # выведет 3. 14

Вызов внешних программ из скрипта на языке PERL

Будучи в известном смысле заменой скриптов shell, Perl обеспечивает поддержку системного взаимодействия, включая вызов внешних программ. В следующих разделах рассматривается несколько способов вызова внешних программ из скриптов Perl. Имейте, однако, ввиду, что позволяя скриптам выполнять системные команды, вы тем самым открываете бреши в системе безопасности вашего узла. Придерживайтесь общего правила не выполнять внешних команд из скрипта на языке Perl. Тем не менее, если вы вынуждены выполнять внешние команды из скрипта, то можете использовать для этих целей встроенные функции system, exec или fork.

Регулярные выражения

На протяжении этой главы вы познакомились с примерами функций для обработки строк. Многие из них основаны на концепции регулярных выражений. Как вы видите из следующих разделов, скрипты языка Perl широко используют регулярные выражения для обработки текста. Если регулярные выражения внове для вас, то не беспокойтесь. Спустя короткое время после того, как вы познакомитесь с несколькими разделами этой главы, регулярные выражения станут для вас просты и понятны.

Обзор регулярных выражений

Регулярные выражения являются причудливым термином, возникшим в компьютерной науке и служащим для обозначения образца, состоящего из символов. Скрипты на языке Perl используют символьные образцы просто для того, чтобы провести анализ входных данных, расщепляя их на части. Часто скрипт может проанализировать входные данные, основываясь на пробелах, запятых, символах табуляции и других разделителях. Но когда входные данные имеют произвольный формат, то лучше всего с такой задачей справляются регулярные выражения.

Синтаксис регулярных выражений

Для сокращения размеров регулярных выражений, Perl использует специальные символы. Таблица 12. 6 содержит список некоторых из символов, используемых скриптами языка Perl в регулярных выражениях.

Табл. 12. 6. Символы, используемые в регулярных выражениях

Символ

Описание

.

Соответствует любому символу (за исключением символа новой строки)

(. . )

Группирует последовательность элементов

+

Удовлетворяет предыдущему образцу оди или большее количество раз

?

Удовлетворяет образцу нуль или один раз

*

Соответствует образцу один или нуль раз

[. . . ]

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

[^. . . ]

Соответствует символу из множества полученного отрицанием

(. . . |. . . |. . . )

Соответствует одной из альтернатив

^

Соответствует началу строки

$

Соответствует образцу в конце строки

{n, m}

Соответствует образцу от n до m раз

{n}

Соответствует образцу точно n раз

{n, }

Соответствует образцу минимум n раз

etc.

Соответствует знаку новой линии, символу табуляции и т. д.



Соответствует на границе слова

B

Соответствует внутри границ слова

D

Соответствует цифре

D

Соответствует не цифре

S

Соответствует пробелу

S

Соответствует не пробелу

W

Соответствует букве или цифре

W

Соответствует символу, не являющемуся ни буквой, ни цифрой

Perl помещает регулярные выражения (образцы, шаблоны) в слэши, т. е. в наклонные черточки, например, в виде /pattern/. Следующий фрагмент программы иллюстрирует регулярные выражения языка Perl:

# the following regular expressions are true if:

/ig/ # string contains 'ig'

/(b|d|f)ig/ # string contains 'big', 'dig' or 'fig'

/[0-9]+/ # string contains a number

/[A-Za-z][A-Za-a0-9_]*/ # string contains an identifier

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

Использование регулярных выражений для поиска по ключевым словам

Скрипты языка Perl используют регулярные выражения для того, чтобы упростить сравнение строк. Для того чтобы проверить, содержит ли строка заданный образец, скрипт может использовать регулярные выражения следующим образом:

if ($str =~ /pattern/)

В данном случае регулярные выражения принимают значение <истинно>, если образец найден в строке ($str). Если строка по содержит образца, то выражение возвращает значение <ложно>. Например, следующее выражение проверяет, содержит ли строка текст WebProgramming:

if ($str =~ /Web Programming/)

Для того, чтобы проверить полное совпадение, выражение должно привязать сравнение к началу и концу строки. Например, следующее выражение имеет значением величину <истинно>, если и только если переменная $str принимает одно из трех значений:<banana>, <bananana>) <banananana>:

($str =~ /^ba(na) {2, 4}$/)

Аналогичным образом, следующее выражение истинно тогда итолько тогда, когда переменная $str содержит слово <the> и не является частью другого слова, такого как <their>.

($str =~ /the/)

Использование регулярных выражений для анализа входных данных

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

$str = " January 1, 1997, ";

($m, $d, $y) = $str =~ /s*(S*)s + (d+)D + (d{4})/;

В этом случае можно прочитать регулярные выражения следующим образом:

? Пропустить вначале любой специальный символ;

? записать все символы, не являющиеся специальными, в переменную $m

? (переменная для обозначения месяцев);

? пропустить специальный символ;

? поместить все цифры в переменную $d (переменная для записи дней);

? пропустить все знаки, не являющиеся цифрами;

? записать четыре цифры в переменную $у (переменная для обозначения лет).

Perl поддерживает также другую форму сравнения с образцом, использующую оператор (=~), который добавляет отрицание результата: (!~). Этот оператор эквивалентен выражению!($str=~/pattern/).

Регулярные выражения для поиска и замены строк

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

$str =~ s/pattern/replacement/;

Например, следующая инструкция заменит слово <colour> на<color>:

$str =~ s/colour/color/;

Небольшая модификация позволяет заменить все слова <colour>на <color>:

$str =~ s/colour/color/g;

В данном случае g в конце выражения указывает языку Perl на необходимость глобальной подстановки.

Используя суффикс i, можно задать выполнение поиска с учетом регистра. В противоположность простой проверке на соответствие образцу, следующее выражение осуществляет также и замену:

$str =~ tr/SearchList/ReplacementList/;

Например, замена всех символов нижнего регистра теми же символами верхнею регистра может быть осуществлена таким образом:

$str =~ tr/a-z/A-Z/; # меняет регистр, с нижнего на верхний

Проанализируйте сами следующий пример:

$letters = "abcde";

print "$letters " # Выведет abcde

$letters =~ tr/a-z/A-Z/;

print "$letters " # Выведет ABCDE

Похожие статьи




Подпрограммы - Язык программирования PERL. Сфера применения

Предыдущая | Следующая