Документ взят из кэша поисковой машины. Адрес оригинального документа : http://kodomo.fbb.msu.ru/FBB/year_09/perl/3.doc
Дата изменения: Mon Feb 21 11:59:52 2011
Дата индексирования: Mon Oct 1 22:56:02 2012
Кодировка: koi8-r

Массивы
Бывает необходимо работать с набором однотипных данных (например, телефоны
в записной книжке). Заводить отдельную переменную для каждого данного
неудобно (например, их может быть 500). Поэтому придумали массивы.

Перед именем переменной-массива стоит разыменовывающий префикс @
(напоминающий своим видом, что это array - "массив").

Список значений помещается в массив с помощью операции присваивания.

my $v = "test";

my @array = (1,3.4,"dda",$v);

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

@array = (1..12);

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

my @ar1 = @array;

Если попытаться присвоить скалярной переменной массив, то ее значением
станет размер массива

$array_size = @months; # число элементов (размер) массива
Можно вставлять одни массивы в другие:

@small = (3, 4, 5); # этот массив будет вставлен в другой
@big = (1, 2, @small, 6 .. 9); # то же, что @big = (1 .. 9);
@big = ((1, 2), (3 .. 5), (6 .. 9)); # то же, что и выше

@all = (@first, @second); # объединить два массива в один

Элементы массива

Элементы массива - это скалярные величины, доступ к которым происходит по
их порядковому номеру (индексу). Поскольку элемент массива - это скаляр, то
его обозначение состоит из префикса $ перед именем массива, за которым в
квадратных скобках стоит индекс. Индексы элементов массива задаются целыми
числами, начиная с нуля.

@array # переменная-массив, хранящая список
$array[0] # первый элемент массива с индексом 0
$array[1] # второй элемент массива с индексом 1
$array[$i] # i-й элемент массива, считая с 0
$array # скаляр, не имеющий отношения к массиву @array

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

$array[-1] # последний элемент, то есть 1-й от конца
$array[-2] # предпоследний элемент, то есть 2-й от конца
$array[-$n] # n-й элемент массива, считая с конца

Индекс последнего элемента массива, который всегда на единицу меньше
размера массива, можно узнать, указав специальный префикс $# перед именем
массива:

$last_index = $#array; # индекс последнего элемента @array

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

@birthday = (18, 12, 1987);
$birthday[5] = 'Perl'; # размер @birthday теперь 6
# значение $birthday[3] и $birthday[4] не определено

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

$array[$#array+100] # неопределенно

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

for (my $i = 0; $i < @array; $i++) {
print "$array[$i] ";
}

Можно то же самое записать еще более кратко в виде цикла foreach который
поочередно перебирает все элементы массива:

foreach my $i (@array){

print $i."\n";

}

как и многое в перле это можно сократить, используя переменную $_, куда все
записывается по умолчанию:

print "$_ " foreach @array;

Бывает нужно поменять значения некоторых элементов массива. Например, нам
нужно поменять местами элементы массива с индексами 4 и 6

my $el = $array[4];

$array[4]=$array[6];

$array[6]=el;

В Perl есть удобная форма обращения к нескольким элементам массива
одновременно, называемая срезом массива. Срез (slice) - это набор элементов
массива, заданный перечислением индексов этих элементов. Можно извлекать
одновременно несколько элементов массива и работать с ними:

@array[4,6]=@array[6,4];




@array[0,1] # то же, что ($array[0], $array[1])
@array[5..7] # то же, что ($array[5],$array[6],$array[7])
@array[3,7,1] # то же, что ($array[3],$array[7],$array[1])
@array[@indexes] # срез, заданный массивом индексов
# присвоить значения пяти элементам:
@array[5..9] = ("FreeBSD", "Linux", "MacOS", "NetWare", "Windows");
# поменять местами значения 1-го и последнего элементов:
@array[0,-1] = @array[-1,0];
# напечатать элементы с индексами от $start до $finish
print @array[$start .. $finish];

Функции работы с массивами (для самостоятельного изучения)

Для работы с таким популярным типом данных, как массивы, в Perl существует
много удобных функций.

|функция|что делает |пример |
|shift |удаляет из массива первый |while (my $first = shift @array) { |
| |элемент, возвращая его значение|# пока @array не опустеет |
| | |print "Обработан элемент $first."; |
| | |print "Осталось ", scalar @array, "|
| | |элементов\n"; |
| | |} |
|unshift|вставляет свои аргументы в |my @arr = (4..10); |
| |массив перед первым элементом, | |
| |сдвигая существующие элементы |unshift @arr, 1, 2, 3; |
| |вправо | |
| | |print "обработан $_\n" foreach |
| | |@arr; |
|push |добавляет элементы в конец |my @arr = (1..7); |
| |массива | |
| | |push @arr, 8, 9, 10; |
| | | |
| | |print "обработан $_\n" foreach |
| | |@arr; |
|pop |извлекает последний элемент |my @arr = (1..10); |
| |массива | |
| | |while(my $last=pop @arr){ |
| | | |
| | |print "обработан $last\n" |
| | | |
| | |}; |
|splice |удаляет идущие подряд элементы |my @array = (1..7); # |
| |массива, заданные индексом |исходный массив |
| |первого элемента и количеством |my $offset = 2; my $size = 4; # |
| |удаляемых элементов, и заменяет|смещение и размер удаляемого |
| |их новым массивом (если он |массива |
| |указан), возвращая массив |my @deleted = splice @array, |
| |удаленных элементов. |$offset, $size, ('новый', |
| | |'массив'); |
| | |# в @array теперь (1, 2, 'новый', |
| | |'массив', 7) |
| | |# в @deleted попали 4 удаленных |
| | |элемента (3, 4, 5, 6) |
|sort |не изменяя своего аргумента, |my @unsorted = (12, 1, 128, 2, 25, |
| |возвращает массив, |3, 400, 53); |
| |отсортированный по возрастанию |my @sorted = sort @unsorted; |
| |строковых значений элементов |# в @sorted будет (1, 12, 128, 2, |
| |исходного массива. Если нужно |25, 3, 400, 53) |
| |упорядочить массив другим |@sorted = sort {$a <=> $b } |
| |образом, то нужно в качестве |@unsorted; |
| |первого аргумента функции |# в @sorted будет (1, 2, 3, 12, 25,|
| |указать блок, выполняющий |53, 128, 400) |
| |сравнение двух элементов | |
| |сортируемого массива и | |
| |возвращающий значения -1, 0, 1 | |
| |- они означают, что первый | |
| |элемент меньше, равен или | |
| |больше второго | |
|reverse|возвращающает инвертированный |my @array = ('Do', 'What', 'I', |
| |массив, не меняя исходного |'Mean'); # исходный массив |
| | |my @backwards = reverse @array; |
| | |#исходный массив остается |
| | |неизменным |
| | |# в @backwards будет ('Mean', 'I', |
| | |'What', 'Do') |
|map |позволяет выполнить действия |my @result = map $_*10, (11, 32, |
| |над всеми элементами массива |55); # работа с массивом |
| | |# в @result будет (110, 320, 550) |
| | |my @array = (11, 32, 55); # |
| | |исходный массив |
| | |@result = map {if ($_ > 20) |
| | |{$_*=10;} else {$_;} } @array; |
| | |# в @result будет (11, 320, 550) |
|join |преобразует каждый элемент |my @array = (5..10); # объединяемый|
| |массива к строке, объединяет | |
| |отдельные элементы массива в |#массив |
| |одну строку, вставляя между |my $delimiter = ':'; # разделитель |
| |элементами указанный | |
| |разделитель, и возвращает |#элементов массива в строке |
| |полученную строку в качестве |my $string = join $delimiter, |
| |результата |@array; # объединение в строку |
| | |# теперь $string содержит |
| | |'5:6:7:8:9:10' |
|split |разделяет строку по указанному |my $string = '5:6:7:8:9:10'; # |
| |разделителю и возвращает массив|исходная строка |
| |составляющих строк |my $delimiter = ':'; # |
| | |разделитель подстрок |
| | |my $limit = 3; # |
| | |число элементов |
| | |my @strings = split $delimiter, |
| | |$string, $limit; # разделение |
| | |# в @strings содержится ('5', '6', |
| | |'7:8:9:10') |


Потоки ввода-вывода

В программе обращение к потоку ввода-вывода производится через файловый
манипулятор (file handle). При запуске любой программы автоматически
открывается три потока: стандартный ввод (stdin), стандартный вывод
(stdout) и стандартный поток вывода ошибок(stderr). Со стандартными
потоками в Perl связываются три предопределенных файловых дискриптора:
соответственно STDIN, STDOUT и STDERR.

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

Связывание имени файла с пользовательским файловым дискриптором в программе
выполняется с помощью операции open(), открывающей поток обмена данными с
указанным файлом. Требования надежности рекомендуют обязательно проверять
все операции ввода-вывода на успешное завершение. Поэтому в случае
возникновения ошибки при открытии файла программа обычно аварийно
завершается с помощью функции die(), которая может выводить диагностическое
сообщение.

# открыть для чтения файл по имени, взятом из $file_name
open FILE, $file_name
# или аварийно завершить программу с выдачей сообщения
or die("Ошибка открытия файла $file_name: $!\n"); #

$!-- сообщение системы

Иногда прежде чем что-то делать с файлом надо проверить есть он или нет.
Для этого есть оператор -e:

if(-e $fname){

open FILE,$fname

}else{

print "file does not exist!\n";

}

При открытии файла функции, помимо файлового манипулятора и имени файла в
файловой системе (абсолютного или относительного), указывается режим
открытия файла. По умолчанию файл открывается на чтение.



Таблица 9.1. Основные режимы открытия потоков ввода-вывода
|Обозначени|Режим открытия |Пример использования |
|е | | |
|< |Чтение (существующего файла с |open(FILE, |
| |начала) |' |> |Перезапись (с начала файла) |open(FILE, |
| | |'>/temp/buffer.txt') |
|>> |Дозапись (в конец файла) |open(FILE, |
| | |'>>/temp/buffer.txt') |
Связь файлового дискриптора в программе с обрабатываемым файлом разрывается
функцией закрытия потока close(), закрывающей поток ввода-вывода. Ей
передается файловый дискриптор открытого файла:

close FILE;

Построчный ввод-вывод

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


$input = <>; # чтение строки в $input из STDIN
$in = ; # чтение строки в $in из потока FILE

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


open FILE, "$file" or die "Ошибка открытия: $!";
while (my $line = ) { # чтение строки в переменную $line
chomp $line; # удаление разделителя строк
print length $line, " $line\n"; # обработка строки
}
close FILE or die "Ошибка закрытия: $!";

Если слева стоит переменная-массив, операция чтения "кристалл" возвращает
массив всех строк с разделителями записей. Так, например, можно считать
файл в массив, попутно отсортировав его:


@lines= sort(); # в @lines отсортированные строки из $fh


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


print($list, $of, $output, $values); # вывод в STDOUT
print FILE $list, $of, $output, $values; # вывод в FILE


Задачи:

на 1 балл:

1. Написать программу которая просит у пользователя ввести набор чисел.
Когда пользователь введет пустую строку спросить у него имя файла и
записать в этот файл все введенные числа, предварительно их
отсортировав, а также среднее и дисперсию введенных чисел. Формат
выдачи:

Data: value1, value2, value3,.

Average: value

Dispersion: value

2. Написать программу которая просит пользователя ввести название файла,
который содержит список слов (каждое слово на новой строке). Далее
программа распечатывает все слова в алфавитном порядке и спрашивает
хочет ли пользователь добавить слово, если нет - программа заканчивает
работу, если да - просит пользователя ввести слово, и перезаписывает
файл (добавив в него новое слово) упорядочивая слова в ОБРАТНОМ
алфавитном порядке.

3. Написать программу которая спрашивает у пользователя имя файла, читает
из него нуклеотидную последовательность (игнорируя все символы кроме
'ATGCU'), после этого спрашивает у пользователя имя другого файла и
записывает в него: последовательность (оставив в ней только правильные
символы), тип последовательности (RNA, DNA или STRANGE), и частоты
всех нуклеотидов.

на 2 бала

1. Написать программу - записную книжку. Программа спрашивает у
пользователя имя файла с записной книжкой, если введенного файла нет -
сообщает об этом и предлагает создать файл с введенным именем. Если
пользователь отказывается, программа просит ввести другой вариант
файла. Файл содержит записи в формате Имя, телефон. Каждая запись на
новой строке. Далее программа спрашивает что пользователь хочет
сделать: выйти (exit), ввести новую запись (add), или найти запись
(search). Если пользователь выбирает выйти, программа сохраняет все
изменения в файл и завершает выполнение. Если пользователь выбирает
добавить, программа просит ввести имя, потом телефон, потом печатает
новую запись и строчку «запись успешно добавлена» и ждет дальнейших
команд. Если пользователь выбирает поиск - просит ввести имя. Далее
находит все записи у которых имена начинаются с того что ввел
пользователь и распечатывает их.