Объявление

Объявление массивов очень просто: my @mass(); Но массив, как и хэш, можно и не объявлять, перл это умеет делать сам.

Доступ к элементам массива осуществляется например таким образом(выводится случаный элемент массива): print $mass[rand $#mass];

В переменной $#mass содержится размер массива-1, т.к. нуумерация элемента массива начинается с нулевого элемента.

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

Постраничный вывод новостей с разбиением по датам

Предположим есть файл news.dat со строками(не суть что разделитель, разделитель определяется переменной $/, которую можно в начале кода переопределить) вида: 20010717<A href="http://www.netoscope.ru/news/" target=_new>news1</a>&nbsp;&nbsp;&nbsp;&nbsp;[Нетоскоп] 20010717<A href="http://www.utro.ru/news/" target=_new>news2</a>&nbsp;&nbsp;&nbsp;&nbsp;[Утро] 20010718<A href="http://www.compulenta.ru/" target=_new>news3</a>&nbsp;&nbsp;&nbsp;&nbsp;[Компьюлента] 20010718<A href="http://www.compulenta.ru" target=_new>news4</a>&nbsp;&nbsp;&nbsp;&nbsp;[Компьюлента] 20010718<A href="http://www.kommersant.ru/news/" target=_new>news5</a>&nbsp;&nbsp;&nbsp;&nbsp;[КоммерсантЪ] 20010719<A href="http://www.echo.msk.ru/7news/" target=_new>news6</a>&nbsp;&nbsp;&nbsp;&nbsp;[Эхо Москвы] 20010719<A href="http://www.echo.msk.ru/7news/" target=_new>news7</a>&nbsp;&nbsp;&nbsp;&nbsp;[Эхо Москвы]

где даты поставлены задом наперед, сначала год, затем месяц, затем день, так сравнивать легче, ибо год максимален, месяц тоже максимален, и деть тоже максимален. Иначе для сортировки по дате пришлось бы вводить двенадцатиричную систему счисления для месяцев и затем 60-тиричную систему счисления для часов, минут и секунд.

Приведенная ниже программа позволяет реализовать постраничный вывод текста, с линейкой прокрутки текста наподобие результатов, выдаваемых обычными поисковиками: #!/usr/bin/perl -wT print "content-type: text/html\n\n"; use CGI 'param'; $pos = param('pos'); $n = 5; $k = 5; $url = "q.pl"; open F, "<news.dat"; @mass=<F>; close F; @m1=grep{!$_{$_}++} map{/^(\d\d\d\d\d\d\d\d)/} @mass; foreach $u(0 .. $#m1){ foreach $n(@mass){ chomp $m1[$u]; push @{$ha{$m1[$u]}}, $n if($n=~m/^$m1[$u]/) } } print "<a name=top>"; for $k(reverse sort keys %ha){ $k=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; push(@re, " <a href=\"#$k\">$k</a> "); } print "<center>"; &res(@re); print "</center>"; for $k(reverse sort keys %ha){ $m=$k; $m=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; $tr="<b><a name=\"$m\">$m</b> <a href=\"#top\">top</a><ul>"; foreach $im(@{$ha{$k}}){ $im=~s!$k|<br>!!; $tr.="<li>$im";} $tr.="</ul>"; push @res, "$tr\n"; } push @res, ""; &res(@res); sub res{ local @res=@_; if($#res>$n-1){ print "<p><center><font size=-1><b>"; foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); } foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->'){push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } } print $back[$#back]; print @nach; foreach $elem1(@vtoroj){ if ($elem1/$n<=$pos/$n+$k && $res[$#res] ne '<!--end-->'){ print " | <a href=\"$url?pos=$elem1\">".($elem1/$n+1)."<\/a> \n"; } if($#vtoroj > $k-1 && $res[$#res] ne '<!--end-->'){ push(@back1, "<a href=\"$url?pos=".($elem1)."\">>><\/a>") } } print "$back1[0]</b></font></center>"; } $#pervij=-1; $#vtoroj=-1; $#back=-1; $#nach=-1; $#back1=-1; print "<p>"; for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]} } Разберем работу программы: @m1=grep{!$_{$_}++} map{/^(\d\d\d\d\d\d\d\d)/} @mass;

составляем массив цифр, т.е. массив дат, map{/^(\d\d\d\d\d\d\d\d)/} @mass составляет список цифр, указанных в регулярном выражении. Следующая строчка grep{!$_{$_}++} - убирает одинаковые даты, т.к. в списке новостей может быть несколько новостей за один день. Получаем массив @m1 с днями, которые были с новостями. foreach $u(0 .. $#m1){ foreach $n(@mass){ chomp $m1[$u]; push @{$ha{$m1[$u]}}, $n if($n=~m/^$m1[$u]/) } }

создаем хеш массивов @{$ha{$m1[$u]}}, в которых определенному дню будет соответствовать несколько новостей. for $k(reverse sort keys %ha){ $k=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; push(@re, " <a href=\"#$k\">$k</a> "); } print "<center>"; &res(@re); print "</center>";

выводим линейку дат, если при выводе 5 дней(значение числа дней содержится в переменной $n = 5;) число новостей таково, что будет помещаться на более чем одной странички, вобщем для быстрой навигации. for $k(reverse sort keys %ha){ $m=$k; $m=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; $tr="<b><a name=\"$m\">$m</b> <a href=\"#top\">top</a><ul>"; foreach $im(@{$ha{$k}}){ $im=~s!$k|<br>!!; $tr.="<li>$im";} $tr.="</ul>"; push @res, "$tr\n"; } push @res, ""; &res(@res);

выводим из хеша список новостей по одной штуке, независимо от даты. Далее следует код вывода линейки прокрутки для постраничного вывода результатов. sub res{ local @res=@_; if($#res>$n-1){ print "<p><center><font size=-1><b>"; foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); } foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->'){push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } } print $back[$#back]; print @nach; foreach $elem1(@vtoroj){ if ($elem1/$n<=$pos/$n+$k && $res[$#res] ne '<!--end-->'){ print " | <a href=\"$url?pos=$elem1\">".($elem1/$n+1)."<\/a> \n"; } if($#vtoroj > $k-1 && $res[$#res] ne '<!--end-->'){ push(@back1, "<a href=\"$url?pos=".($elem1)."\">>><\/a>") } } print "$back1[0]</b></font></center>"; } $#pervij=-1; $#vtoroj=-1; $#back=-1; $#nach=-1; $#back1=-1; print "<p>"; for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]} }

локализуем массив @res: local @res=@_; - получили массив, переданный попрограмме. Далее if($#res>$n-1){blah blah blah} если число элементов массива больше, чем 5, то показываем строчку прокрутки.

Разбиваем массив @res на массивы до текущей страницы(@pervij) и после текущей страницы(@vtoroj): foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); }

размерность массивов @pervij и @vtoroj кратна(кратность определяется оператором %) числу $n, т.е. это массивы до текущей страницы и после текущей страницы, в броузере, если пользователь находится допустим на 10 странице результатов до текущей все то, что до цифры без ссылки, после текужей это все то, что после цифры без ссылки, включая линейки прокрутки << и >>: << 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 >>

Эти массивы содержат число пятерок(для $n=5;) элементов массива @res. foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->'){push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } } Цикл для показа элементов предыдущих страниц << 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

т.е. если $elem/$n>=$pervij[$#pervij]/$n-$k, то это значит, что выбираются страницы элементов до текущей позиции, включая её, т.е. 2, 3, 4, 5 и 6 - цифра 7 это текущая позиция, которая определяется условием if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->'). Зачем тут стоит <!--end--> будет видно позднее в разборе админской части этой ленты новостей.

Условие if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") }

значит что если существуют элементы массива @pervij больше, чем $k=5, то для таких елементов нужно ставить знички прокрутки << и >>. Для массива @vtoroj условия определяются аналогичным образом, учитывая, что элементы для него должны быть больше определенного числа $pos, которое определяет текущее значение показываемой пятерки дат. Вывод самих новостей осуществляется циклом for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]}

который берет элементы массива $res[$i] до элемента $n, т.е. допустим пользователь находится на странице 10, значит должен производится вывод новостей с 50 по 55-ю включительно.

Вывод результатов помещен в подпрограмму, т.е. существует некая переносимость кода из одного скрипта в другой. В скрипте подпрограмма используется дважды, когда нужно вывести число дат по $n штук и когда нужно вывести сами новости в количестве $n штук на страничку.