Array elements access instances in the following way (a randmon array element):
print $mass[ramd $#mass];
Variable $#mass contains array size-1 because arrays are numerated from zero.
Usage examples.
Page views by dates.
Presuppose, we have a file news.dat with strings like the following:
20010717<A href="http://www.cnn.com/news/" target=_new>news1</a> [CNN]
20010717<A href="http://www.bbc.com/news/" target=_new>news2</a> [BBC]
20010718<A href="http://www.zend.com/" target=_new>news3</a> [Zend]
The program given below allows to display page listings with scrolling like the results generated by search engines:
#!/usr/bin/perl -wT print "content-type: text/html
"; use CGI 'param'; $pos = param('pos'); $n = 5; $k = 5; $url = "q.pl"; open F, "<news.dat"; @mass=<F>; close F;
@m1=grep{!$_{$_}++} map{/^(dddddddd)/} @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|^(dddd)(dd)(dd)|$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|^(dddd)(dd)(dd)|$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 "; } 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> | ");} } 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> "; } 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] } } |
Let's go deeper in the program:
@m1=grep{!$_{$_}++}
map{/^(dddddddd)/} @mass;
create an array of digits, where dates array map{/^(dddddddd)/} @mass makes a list of digits pointed in the regular expression. The next line grep{!$_{$_}++} removes the same dates because there can be news for the same date in the news list. We've got an array @m1 with the news days.
foreach $u(0 .. $#m1){
foreach $n(@mass){
chomp $m1[$u];
push @{$ha{$m1[$u]}}, $n if($n=~m/^$m1[$u]/)
}
}
creating hash of arrays @{$ha{$m1[$u]}} where several news can be for the same day.
for $k(reverse sort keys %ha){
$k=~s|^(dddd)(dd)(dd)|$3.$2.$1|;
push(@re, " <a href="#$k">$k</a> ");
}
print "<center>";
&res(@re);
print "</center>";
display the line of dates. If there are 5 days in the output, they will be displayed on more than one page, for faster navigation.
or $k(reverse sort keys %ha){
$m=$k; $m=~s|^(dddd)(dd)(dd)|$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
";
}
push @res, "";
&res(@res);
Take news from the hash one by one, not depending on date. Then the scrollbar for page views is displayed.
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> |
");}
}
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>
";
}
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]
}
}
Localize array @res: local @res=@_; - got an array, inputed to the subprogram. Then if($#res>$n-1){
blah blah blah
} show the scroll if array size is more then 5.
Split the array @res on arrays until the current page (@pervij) and after the current page (@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);
}
Sizes of @pervij nad @vtoroj are divizable by $n, these are the array until the current page and after the current page.
This will display page numbers and scroll links in the browser: << 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 >>
These arrays contain number of five elements blocks (for $n=5) of @res array elements.
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> |
");}
}
if($#pervij > $k && $res[$#res] ne '<!--end-->'){
push(@back, "<a href="$url?pos=".($pos-$n).""><<</a>")
}
}
Cycle to display the elements of the previous pages << 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
If $elem/$n>=$pervij[$#pervij]/$n-$k, then it means that the pages elements until the current position are selected.
What for <!--end--> is here? It will be explain later.
Condition
if($#pervij > $k && $res[$#res] ne '<!--end-->'){
push(@back, "<a href="$url?pos=".($pos-$n).""><<</a>")
}
means that if there are elements of @pervij that are bugger then $k=5, then these elements should have scrolling signs ("<<" and ">>").Output of the news themselves is implemented with the helpof the following cycle:
for ($i=$pos; $i<$pos+$n; $i++){
print $res[$i]
}
that takes the elements of $res[$i] array until element $n. Presuppose user is on page 10, this means that news from 50 to 55 should be outputed.
Output of the results is given in the subprogram that provides some portability from one script to another. In the script the subprogram is used twice: when we need to output the number of dates until $n and when we need to output the news themselves by $n times on a page.