Perl

Mureakuha

Loikkaa: valikkoon, hakuun

Oppaan tarkoitus on olla Perl-kielen alkeet selvittävä opas niille ihmisille, joilla on vähän tai ei juuri ollenkaan ohjelmointikokemusta. Kenelle tahansa ohjelmointia enemmän harrastaneelle tämä ei liene muuta kuin parin tunnin aamupala. Linux-käyttöjärjestelmästä sinun täytyy tietää sen verran että saat Linux-konsolin auki joko aidossa Linux- ympäristössä tai sitten puttyn tai telnetin tms. ohjelman kautta Windowsissa. Mikäli et tiedä ohjelmoinnista yhtään mitään, voit seurata monistetta soveltaen mutta suosittelen tutustumista aliohjelmien tekoon ja tiedostoon kirjoittamisen/tiedostosta lukemisen treenaamiseksi C/C++-kieltä, koska Perlissä nämä asiat eivät ole yhtä yksinkertaisia. Mikäli taas nämä asiat ovat jo C:n pohjalta hallussa ei ole paljoa pelkoa ettetkö pysyisi kärryillä.

Sisällysluettelo

Perl?

Perl on Linuxissa yleisesti käytetty skriptikieli. Skriptikielen ja tavallisen käännettävän kielen erona on ainoastaan se, että käännettävissä kielissä kääntäjä tekee tiedoston, mikä sitten ajetaan kun halutaan joten alkuperäinen koodi tulee ohjelman toiminnan kannalta tarpeettomaksi. Skriptikielessä taas koodia käännetään samalla aikaa kun koodia luetaan, joten siinä alkuperäinen koodi on välttämätön ohjelman toimimiselle.

Kulttuuri

Hyvin usein tutoriaaleissa jätetään kertomatta kielestä mitään. Sen historiasta tai kulttuurista ei kerrota mitään. Perlin kanssa on tärkeää tietää vähän kulttuuriakin.

Historia

Perlin kehitys alkoi vuonna 1987 Larry Wallin toimesta. Saman vuoden joulukuussa Wall julkaisi Perlin ensimmäisen version comp.sources.misc-uutisryhmään. Perl2 julkaistiin jo seuraavana vuonna ja kielen suosio kasvoi. Perl2:ssa oli paranneltu säännöllisten lausekkeiden moottori. Perlin seuraava versio tuki jo binääristä dataa.

Vuonna 1993 Wall rupesi kehittämään Perl5:tä. Kun Perl5 julkaistiin, se sisälsi monia uusia ominaisuuksia kuten oliot, viittaukset, pakkaukset ja moduulit. Moduulien avulla voi lisätä kieleen ominaisuuksia muuttamatta tulkkia. Tänäkin vuonna Perl5:tä kehitetään ahkerasti. Version 5 myötä saatiin Perliin tuki Unicode-merkistökoodaukselle.

Perl6:ta kehitetään vielä ja se tullaan ajamaan Parrot-nimisen virtuaalikoneen päällä ja sisältää uudenlaisen olio-ohjelmointiympäristön.

Toteutus

Perl on toteutettu tulkkina ja laajoina moduulikirjastoina. Tulkki on kirjoitettu C:llä ja moduulit Perlillä tai C:llä. Tulkki on yli 150 000 riviä C-koodia ja kääntyy noin 1 Mt:n kokoiseksi ohjelmaksi riippuen järjestelmästä. Jakelun mukana tulee noin 500 moduulia, jotka sisältävät 200 000 riviä Perliä ja 350 000 riviä C-koodia. Suuri osa C-koodista on merkistökoodaustaulukoita.

Perl-koodin suoritus sisältää kaksi vaihetta. Ensiksi tulkki parsii ohjelmasta syntaksipuun, ja sen jälkeen suorittaa sen liikkuen syntaksipuussa.

Sanonnat

Perlille on vakiintunut monia sanontoja. TMTOWTDI - There's more than one way to do it (on useampi kuin yksi tapa tehdä se). Yksi esimerkki tästä on for-silmukka.

# Voit kirjoittaa.
 
for $alkio ( @taulukko ) {
    print $alkio;
}
 
# Tai voit kirjoittaa
print for( @taulukko );

Toinen sanonta on Make easy tasks easy and difficult tasks possible (tehdään helpot asiat helpoiksi ja vaikeat mahdollisiksi).

Mitä tämä opas käsittelee?

Opas käsittelee Perlin alkeita Linux-käyttöjärjestelmässä. Esimerkkitekstieditorina käytämme Picoa, mutta tietysti mikä tahansa muukin editori käy (Emacs, vi, vim, sed). Tämä opas ei käsittele näitä, kuten ei myöskään Windows-käyttöjärjestelmässä toimivaa ActivePerliä tai Perlscriptiä. Myös CGI-ohjelmat, jotka tehdään useimmiten perlillä on rajattu ulkopuolelle, mutta suosittelen CGI-ohjelmoinnista kiinnostuneita tutustumista ensin tähän oppaaseen.

Käyttöjärjestelmä toimii tarkemmin sanottuna Linux Red Hat, mutta kaikki muutkin Linuxin versiot pitäisi toimia samalla tavalla.

Konfigurointi ja Perlin asentaminen

Tämän oppaan päätarkoitus ei ole konfiguroinnin tarkastelu, mutta silti pari sanaa on välttämätöntä: Kun sinulla on Linux-konsoli käytössä (joko puttyn, telnetin yms. kautta tai sitten aidossa Linux-ympäristössä) kirjoita siihen which perl tai whereis perl. Tämä käsky antaa rivin, joka ilmaisee missä hakemistossa Perl-tulkki on. Yleensä Linux-käyttöjärjestelmässä Perl tulee vakiona, mutta se on voinut jäädä asentamatta. Kuitenkin, kone antaa polun joka on omassa koneessani /usr/bin/perl, mutta se on usein myös /usr/local/bin/perl.

Jos polku on sinulla erilainen, niin käytä sitä äläkä minun polkuani(se mihin tätä käytetään selvitetään myöhemmin). Jos kone ilmoittaa että ohjelmaa ei löydy, niin varmista että /usr/bin-hakemisto sisältyy PATH-muuttujaan komennolla "echo $PATH". Jos ei sisälly, niin saat sen lisättyä käskyllä

export PATH=$PATH:/usr/bin

kokeile tämän jälkeen "which perl"-komentoa uudestaan. Jos kone antaa tälläkin kerralla virheilmoituksen niin perliä ei ole asennettu. Voit asentaa sen Todennäköisesti Linuxin asennus-CD-ROM-levyltä tai sen voi ladata internetistä osoitteesta http://www.perl.com/CPAN/ports/index.html (valitse oma käyttöjärjestelmäsi, itse käytän Red Hat Linuxia). Internetistä asentaminen onnistuu yksinkertaisesti siirtymällä siihen hakemistoon mihin latasit ja purit tiedoston (suosittelen /usr/bin/-hakemistoa) ja antamalla käskyn "rpm -i perl*".

Jos käytössäsis on distron oma paketinhallinta, Perlin asentaminen onnistunee sen avulla. Esimerkiksi Debianissa voit asentaa sen helposti komennolla "apt-get install perl".

ActiveState jakaa Perlin MSI-installeria Windowsille. Sen saa ActiveStaten sivuilta.

Hello World

Tämän osion tarkoitus on yksityiskohtaisesti selittää miten alkeellinen "hello world" ohjelma tehdään ja ajetaan Pico-editoria (nano on Pico-klooni, joten se toimii samalla tavalla) käyttäen. Olet avannut Linux-konsolin. Seuraavaksi tehdään Picolla "Hello World"-ohjelma. Kirjoita pico hello.pl

Tämä käsky avaa tekstieditorin, jolloin voi muokata tiedostoa hello.pl. Kirjoita editoriin seuraava koodi.

#!/usr/bin/perl -w
 
# tulostetaan Hello world!
print "Hello world!\n";

Tallenna tiedosto ja sammuta editori. Tämän jälkeen tiedostolle pitää antaa suoritusoikeudet; chmod +x hello.pl. Sen jälkeen voi ajaa ohjelman.

$ ./hello.pl
Hello world!

Näin näytölle tulostuu teksti "Hello world!", ja olet ajanut juuri ensimmäisen Perl-ohjelmasi! Jos perl-ohjelmaa ei löydy, kokeile etsiä se whereis perl-komennolla. Jos perl on itse käännetty, se saattaa löytyä /usr/local/bin/-kansiosta

Käydäänpä läpi hello world-ohjelma yksityiskohtaisesti. Ensimmäinen rivi kertoo komentotulkille, että tiedosto suoritetaan ohjelman /usr/bin/perl läpi, ja sille annetaan parametriksi -w. -w-parametri kertoo, että perl tulostaa kaikki varoitukset. Varoitukset saa myös käyttöön käyttämällä warnings-pragmaa (tästä lisää myöhemmin [toivottavasti]).

Kolmannella rivillä on kommentti. Kommentti alkaa #-merkillä ja jatkuu rivin loppuun asti.

Neljännellä rivillä tulostetaan tekstiä. print-funktion parametriksi annetaan "Hello world!\n", jossa \n-tarkoittaa rivinvaihtomerkkiä. Laukseke päättyy puolipisteeseen.

Perlin versiossa 6 (kehitteillä) tulee olemaan say-funktio, joka tulostaa automaattisesti rivinvaihdon tekstin perään, joten se on kuin Pascalin writeln-funktio.

Muuttujat

Skalaari

Perlin muuttujiin voidaan tallentaa tietoa eri muodoissa. Yleisin muuttuja on skalaari, joka alkaa aina $-merkillä. Skaalarin arvo voi olla joko merkkijono, numero tai viittaus.

#!/usr/bin/perl -w
use strict;
 
my $muuttuja = 5;
print $muuttuja ."\n";

my-avainsana määrittää muuttujan paikalliseksi, ja se on voimassa lohkon loppuun asti.

Jos muuttujaan pitää säilöä pitkiä lukuja, voi numeroita erotella alaviivalla.

my $miljardi = 1_000_000_000;

Pisteoperaattorilla yhdistetään merkkijonoja. Muuttuja $muuttuja muutetaan ensin merkkijonoksi, ja yhdistetään sen jälkeen rivinvaihtomerkkiin. Sen jälkeen yhdistetty merkkijono tulostetaan STDOUTiin.

Luvuille voi käyttää seuraavia matemaattisia operaattoreita.

  • + - Yhteenlasku $muuttuja = $muuttuja + 3;
  • - - Vähennyslasku $muuttuja -= 2;
  • * - Kertolasku $muuttuja *= 2
  • / - Jakolasku $muuttuja = $muuttuja / 4;
  • ** - Potenssi $muuttuja = $muuttuja**2;
  • % - Jakojäännös $muuttuja %= 3;

Näitä operaatioita ei voi luonnollisestikaan käyttää kun skalaarimuuttujaan on sijoitettu tekstiä.

Esimerkkiohjelma pyytää käyttäjää syöttämään kaksi lukua ja laskee ne yhteen. Luvut voivat olla liukulukuja tai kokonaislukuja. Luvut voivat olla myös negatiivisiä.

#!/usr/bin/perl -w
use strict;
 
print "Anna numero\n> ";
 
# luetaan oletuksena STDIN:stä rivinvaihtomerkkiin asti
my $a = <>;
print"Anna toinen numero\n> ";
 
# luetaan toinen numero
my $b = <>;
 
# numeroiden summa muuttujaan $c
my $c = $a + $b;
 
print "Lukujen summa on $c\n";

Ohjelmassa näkyi myös <>-käsky. Se lukee tekstiä erotinmerkkiin asti, joka STDIN:stä tai parametrinä annetusta tiedostosta.

Seuraava ohjelma tulostaa kaiken mitä parametrinä annettu tiedosto sisältää. Voit käynnistää sen esimerkiksi näin: "./ohjelma.pl ohjelma.pl" ja se tulostaa itsensä sisällön.

#!/usr/bin/perl -w
use strict;
 
print for(<>);

Skalaariin voi säilöä myös tekstiä. Teksti tulee lainausmerkkien väliin, ja tarpeen tullessa se voidaan muuntaa myös numeroksi.

#!/usr/bin/perl -w
use strict;
 
my $kymmenen = 1_0;
my $yksitoista = "11";
 
# merkkijono $yksitoista muutetaan numeroksi
# ja verrataan
if($kymmenen<$yksitoista) {
    print "$yksitoista on enemmän kuin $kymmenen\n";
}

Kun skalaariin säilötään merkkijonoja, ne laitetaan lainausmerkkien sisälle. Merkkijonon sisältäessä $-merkillä alkavan sanan sen oletetaan olevan toinen muuttuja, joka interpoloidaan siihen. Myös taulukoita voi interpoloida merkkijonojen sisään.

#!/usr/bin/perl -w
use strict;
 
my $hei = "Hei";
my $merkkijono = "$hei maailma!";
 
print "$merkkijono\n";

Jos halutaan näyttää merkkijonot sellaisenaan voidaan se kirjoittaa heittomerkkien sisäpuolelle. Silloin voidaan kirjoittaa erikoismerkkejä ja ne pysyvät sellaisin, kuin ne on kirjoitettu.

#!/usr/bin/perl -w
use strict;
 
my $hei = 'Hei';
my $merkkijono = '$hei maailma!';
 
print "$merkkijono\n";
print '$merkkijono' ."\n";

Edellinen ohjelma tulostaa

$hei maailma!
$merkkijono

Merkkijonoja voi monistaa x-operaattorilla.

print "foo" x 10;

Tulostaa: "foofoofoofoofoofoofoofoofoofoo".

Merkkijonofunktioita

length $muuttuja
Palauttaa muuttujan $muuttuja pituuden. Jos muuttujaa ei ole annettu palauttaa muuttujan $_pituuden
substr $muuttuja, $sijainti, [$pituus, [$korvaava]]
Muuttaa muuttujaa $muuttuja kohdasta $sijainti pituuden $pituus verran.
chop $muuttuja
Poistaa merkkijonon viimeisen merkin. Käytetään yleensä rivinvaihtomerkin poistamiseen rivin lopusta. Sama kuin "s/.$//s". Palauttaa poistetun merkin. Jos muuttujaa ei anneta käytetään muuttujaa $_.
split $regex, $muuttuja, [$raja]
Pilkkoo muuttujan $muuttuja $regex-säännöllisen lausekkeen perusteella ja palauttaa taulukon. Taulukon koko on enintään $raja
uc $merkkijono
Muuttaa merkkijonon kirjaimet isoiksi. Oletuksena käytetään muuttujaa $_.
lc $merkkijono
Muuttaa merkkijonon kirjaimet pieniksi. Oletuksena käytetään muuttujaa $_.
#!/usr/bin/perl -w
use strict;
 
$\ = "\n";
my $merkkijono = "Hei maailma!\n";
 
# poistetaan rivinvaihto
chop $merkkijono;
 
# korvataan "i " merkkijonolla "[]"
substr($merkkijono, 2, 3) = "[]";
 
print "Merkkijono " .$merkkijono
    ." on " .length($merkkijono) 
    ." merkkiä pitkä.";

Merkkijonoja vertaillaan eq ja ne operaattoreilla. Ne tulevat sanoista "equal" ja "not equal".

#!/usr/bin/perl -w
use strict;
 
my $numero = 11;
my $merkkijono = "11";
 
# tulostaa Samat!
print "Samat!\n" if( $numero eq $merkkijono );

Taulukko

Vähänkin isompien ohjelmien teossa tulee eteen taulukot. Taulukkoon on kätevä säilöä tietoa ja hakea sitä sieltä. Perlissä taulukkoa voi käyttää myös pinona ja jonona shift, unshift, push ja pop- funktioiden avulla.

Taulukko merkitään @-kirjaimella. Taulukon alkiot on indeksoitu numeroin, toisin kuin assosiatiivisessa taulukossa.

my @taulukko = ( "kissa", "koira" );

Nyt taulukko sisältää kaksi kohtaa. Niihin voidaan viitata indeksillä, joka alkaa nollasta.

my $cat = $taulukko[0];

Nyt muuttujan $cat arvo on "kissa".

Tämän jälkeen taulukkoon voi lisätä tavaraa push-funktiolla taulukon perälle tai indeksinumerolla.

$taulukko[2] = "marsu";
push @taulukko, qw/ aasi apina /;

Tässä käytettiin qw-funktiota, joka luo listan sen sisällä olevista sanoista.

Taulukon sisältöä voi yhdistää join -funktiolla, joka ottaa parametrikseen listan. Kun haluamme tulostaa kaikki elukat, ja niiden väliin välilyönti voimme yhdistää taulukon alkiot seuraavasti.

my $elukat = join " ", @taulukko;
# tulostetaan ne
print $elukat;

Merkkijonoja voit hajottaa taulukoihin split-funktiolla, joka osaa hajottaa niitä regexin perusteella. Jos haluat pilkkoa kaikki merkkijonon kirjaimet taulukkoon, voit käyttää sitä näin:

my @kirjaimet = split //, $elukat;
print join ".", @kirjaimet;

Tässä vielä koko koodi:

#!/usr/bin/perl -w
use strict;
$\ = "\n";
 
my @taulukko = ( "kissa", "koira" );
my $cat = $taulukko[0];
 
$taulukko[2] = "marsu";
 
push @taulukko, qw/ aasi apina /;
 
my $elukat = join " ", @taulukko;
print $elukat;
 
my @kirjaimet = split //, $elukat;
print join ".", @kirjaimet;

Assosiatiivinen taulukko

TODO

Tehtäviä

  1. Tee ohjelma, joka kysyy kolme lukua ja laskee niiden keskiarvon
  2. Tee ohjelma, joka kysyy n lukua ja laskee niiden keskiarvon
  3. Tee ohjelma, joka laittaa taulukkoon(yksi kirjain per alkio) käyttäjän syöttämän rivin ja ilmoittaa, montako a-kirjainta siinä on
  4. Tee ohjelma, jolle voi syöttää mielivaltaisen määrän lukuja vaikkapa välilyönnillä erotettuna ja ohjelma laskee ne yhteen.
  5. Tee pienimuotoinen suomi-englanti-sanakirja, joka kysyy käyttäjältä mitä sanaa tulee etsiä. Jos sanaa ei löydy ilmoittaa ohjelma siitäkin. Käytä assosiatiivista taulukkoa.
  6. Tee ohjelma, joka tutkii onko annettu luku alkuluku (vaatii hiukan matematiikan tuntemusta)

Ehtolauseet ja silmukat

Tutustumme ehtolauseisiin if-lauseen kautta. Rakenne on seuraavanlainen:

if(jotain) {
    tee jotain;
}
if(jotain toista) {
    tee jotain toista;
}
else {
    älä tee mitään;
}

Operaattorit == ja != vertailevat lukuja. Merkkijonojen vertailuun on olemassa kaksi omaa operaattoria.

# jos merkkijonot ovat samat
# Equal
if($a eq $b) {}
# jos merkkijonot eivät ole samat
# Not Equal
if($a ne $b) {}

Perlistä löytyvät myös C-sukuisista kielistä tutuksi tulleet loogiset operaattorit: &&, || jne.

Koska perlissä else on lohko ei voida kirjoittaa.

# ei toimi
else if( $x ) {

}

# pitää kirjoittaa näin
else {
    if( $x ) {
    }
}

Sitä varten perlissä on elsif-rakenne, joka vastaa else if-rakennetta.

Ehtolauseiden käytön tehokkaaseen hyödyntämiseen suosittelen logiikan peruskurssia. Toinen paljon käytetty silmukkarakenne on for. Esimerkki on seuraava:

for( $i=1; $i<10 ;$++ ) {
    print "luku on nyt $i\n";
}

for-lauseessa $luku=1 sijoittaa muuttujan arvon ykköseksi, luku<10 on ehtolause, eli operaatiota mikä tulee hakasuluissa for-käskyn jälkeen suoritetaan niin kauan kunnes ehto ei enää täyty. viimeinen luku=luku+1 sijoittaa silmukan joka kierroksella $luku-muuttujan yhtä suuremmaksi. eli em. ohjelmapätkä tulostaa:

luku on nyt 1
luku on nyt 2
luku on nyt 3
...
luku on nyt 9

kun $luku on 9, ei enää seuraavalla kierroksella for-lauseen ehto $luku<10 täyty, joten silmukan suorittaminen loppuu siihen. Myös foreach-silmukka on tutustumisen arvoinen, Koska se on esiintynyt aiemminkin tässä oppaassa niin rajoitan siitä kirjoittamisen yhteen esimerkkiin:

foreach $alkio (@maaliintulojarjestys) {
    print "Kilpailija $alkio\n";
}

Em. ohjelmapätkä tulostaa @maaliintulojärjestys-taulukosta kaikki alkiot joten jos vaikka @maaliintulojarjestys=("ville" "kalle" "jussi"); (Määritä taulukko ennen foreach-funktiota) tulostaa koodi seuraavanlaista: kilpailija ville kilpailija kalle kilpailija jussi

Ohjelman voi kirjoittaa myös lyhyemmin:

for ( @taulukko ) {
    print "Kilpailija $_\n";
}

Tässä käydään läpi taulukon alkiot, ja joka kierroksella taulukon alkio sijoitetaan muuttujaan $_, ja sen muokkaus vaikuttaa myös taulukon alkioon.

Perlistä löytyy myös unless-lohko.

unless( x )

# on sama kuin

if( !( x ) )
#!/usr/bin/perl -w
use strict;

$\ = "\n";

my $i = 4;
my $j = 7;

if( !( $i!=4 || $j!=7 ) ) {
    print "if";
}

unless( $i!=4 || $j!=7 ) {
    print "unless";
}

Aliohjelmat

Kuten jokainen C-kieleen tai mihin tahansa muuhun ohjelmointikieleen tutustunut tietää, jokainen vähänkin laajempi ohjelmointihomma kannattaa suorittaa siten että tietyt aliohjelmat tekevät aina tietyn rutiinin ja palauttaa sen sitten pääohjelmaan. Yksinkertaisin mahdollinen esimerkki on seuraava:

#!/usr/bin/perl -w
sub aliohjelma {
    print "aliohjelma tulostaa\n";
}
aliohjelma();

Aliohjelma määritellään sub-avainsanana avulla. Avainsanan jälkeen määritellään aliohjelmalle nimi. Subin avulla voidaan määrittää myös nimettömiä aliohjelmia; tästä lisää myöhemmin.

Aliohjelma tarvitsee tietysti myös parametrejä.

#!/usr/bin/perl -w

sub max($$) {
    my ($p1, $p2) = @_;
    return ($p1>$p2?$p1:$p2);
}

print max(33, 45) ."\n";

Rivillä 3 määritellään aliohjelma nimeltään max. Se palauttaa isomman kahdesta numerosta. ($$) tarkoittaa, että funktio ottaa kaksi parametriä. Jos niitä yritetään antaa enemmän tulostuu ilmoitus: "Too many arguments for main::max at ....". Jos haluat antaa määrittelemättömän määrän parametrejä, niin laita (@). Voit myös jättää sen osuuden kokonaan pois, jolloin funktiolle voi antaa määrittelemättömän määrän parametrejä.

Jos funktio ottaa esimerkiksi vain yhden parametrin, ja sinun pitää käyttää sitä, voit käyttää sitä suoraan merkinnän $_[n] avulla, jossa n on parametrin numero (alkaen nollasta), eli tässä tapauksessa $_[0].

Neljännellä rivillä otetaan argumentit talteen @_-taulukosta, joka sisältää kaikissa aliohjelmissa aliohjelman parametrit. Sen jälkeen palautetaan isompi kahdesta.

Viimeisellä rivillä ohjelma tulostaa "45".

Aliohjelmaa voi kutsua kahdella eri tavalla; funktio(); ja &funktio; erona on se, että jälkimmäisessä funktio pääsee käsiksi nykyiseen @_-taulukkoon. Seuraava koodi toivottavasti havainnollistaa asiaa.

#!/usr/bin/perl -w
use strict;

$\ = "\n";

sub sum {
    my $total = 0;
    $total += $_ for @_;
    return $total;
}

print sum(1..10);

# asetetaan taulukkoon arvot
@_ = (1..11);

# nyt funktio pääsee käsiksi arvoihin
print &sum;

Palautusarvo

Joskus funktion pitää palauttaa taulukko, mutta vain jos sitä tarvitaan. Jos funktion pitää palauttaa taulukko, niin wantarray on true. Jos funktio ei palauta muita kuin taulukkoja, voidaan käyttää lausetta return unless defined wantarray; toiminnan lopettamiseen.

Seuraavassa koodissa funktio sec2hms-funktio palauttaa tarvittaessa taulukon ja tarvittaessa stringin.

#!/usr/bin/perl -w
use strict;
use constant HOUR => 3_600;

$\ = "\n";

sub sec2hms {
    my ($h, $m, $s);
    
    $s = shift;
    $h = int($s/HOUR);
    $s %= HOUR;
    $m = int($s/60);
    $s %= 60;

    # palautetaanko taulukko
    wantarray ?
        return ( $h, $m, $s ):
        return "$h:$m:$s";
}

# ei haluta taulukkoa
my $time = sec2hms(1337);

print $time;

# halutaan taulukko, ja sijoitetaan arvot
# oikeisiin paikkoihin
my ($ho, $mi, $se) = sec2hms(1338);

print "$ho:$mi:$se";

Tehtäviä

  1. Tee ohjelma, joka laskee keskiarvon taulukossa olevista luvuista
  2. Tee arvauspeli, jossa kone arpoo sattumanvaraisen luvun väliltä 1-10 ja kertoo, onko luku suurempi vai pienempi, kuin käyttäjän arvaama luku. Kun käyttäjä arvaa luvut, ohjelma tulostaa kuinka monennella kerralla käyttäjä arvasi oikein. (rand())

Viittaukset

Mikä on viittaus? Yksinkertaisimmin: Se on tieto, joka kertoo mistä löytyy tiedot. Eli voin sanoa esimerkiksi "Katso kirjasta Sinuhe Egyptiläinen sivulta 5 rivi 6". Silloin kerron, että tarvittava tieto löytyy sieltä kirjasta.

Perlissä viittaus on aina skalaari, joskaan data, johon viitataan voi olla muuta tyyppiä.

Kun aliohjelmaa kutsutaan, se saa kopion parametreistä, joten parametrien muuttaminen ei muuta niitä muualla kuin aliohjelmassa.

#!/usr/bin/perl -w
use strict;
$\ = "\n";

sub marine($) {
    my $p = shift;
    $p++;
    print "Aliohjelmassa \$p = $p";
}

my $p = 13;

marine( $p );

print "Pääohjelmassa \$p = $p";

Viittauksen voi luoda yksinkertaisesti laittamalla kenoviivan muuttujan nimen eteen.

#!/usr/bin/perl -w
use strict;
$\ = "\n";

my @array = ( 100, 200, 300, 400 );

# viittaus taulukkoon
my $ref_to_array = \@array;

my %hash = ( foo => "bar" );

# viittaus assosiatiiviseen taulukkoon
my $ref_to_hash = \%hash;

my $value = $$ref_to_hash{foo};

# $value = bar
print "$value";

$value = $$ref_to_array[3];

# value = 400
print "$value";

Sitten takaisin ensimmäiseen koodiin.

#!/usr/bin/perl -w
use strict;
$\ = "\n";

# voidaan määritellä funktion parametri
# viittaukseksi, jos ei määritellä näin,
# funktiota kutsuttaessa pitää antaa viittaus
sub marine(\$) {
    my $p = shift;
    $$p++;
    print "Aliohjelmassa \$p = $$p";
}

my $p = 13;

marine( $p );

print "Pääohjelmassa \$p = $p";

Voit myös luoda viittauksia viittauksiin.

#!/usr/bin/perl -w
use strict;
$\ = "\n";

my $i = 1;

my $ref_to_i = \$i;

my $ref_to_ref = \$ref_to_i;

my $ref = \$ref_to_ref;

print "\$i = $$$$ref";

Jos haluat tarkistaa mitä muuttuja $x sisältää voit tehdä sen ref()-funktiolla.

#!/usr/bin/perl -w
use strict;
$\ = "\n";

my %hash = ( foo => "bar", abc => "cde" );
my $ref = \%hash;
my $ref_to_ref = \$ref;
sub marine {};

# ARRAY
print ref( [ 333, 444, 555 ] );
# SCALAR
print ref( \"12345" );
# HASH
print ref( \%hash );
# CODE
print ref( \&marine );
# REF
print ref( \$ref_to_ref );

Viittaukset aliohjelmiin

Jos muuttuja $x sisältää viittauksen funktioon niin se pitäisi tietenkin saada suoritettua, parametreillä. Perlissä on (ainakin) kolme tapaa suorittaa se.

#!/usr/bin/perl -w
use strict;

sub max($$) {
    my ($param1, $param2) = @_;
    return ($param1>$param2?$param1:$param2);
}

# $ref sisältää nyt viittauksen max-aliohjelmaan
my $ref = \&max;

# aliohjelman voi nyt suorittaa kolmella 
# eri tavalla (TMTOWTDI)

# hyvin selkeä tapa
print $ref->(33, 45) ."\n";

# hyvin selkeä tapa myös
print &$ref(21.1, 21) ."\n";

# ei niin selkeä
print &{$ref}(11.0005, 11.00051) ."\n";

Merkkijonojen etsiminen

Aloittelijoille saattaa tulla hieman yllätyksenä se, ettei Perlissä ole replace(lähde, kohde, mikä)-funktiota. Sen sijaan perlissä on s/// ja m//-operaattorit.

Oletkin jo varmasti IRCissä törmännyt perlittäjiin, jotka ovat kirjoittaneet:

<Tuntematon> Mihin menete tänään?
<Tuntematon> s/menete/menette/

Tässä Tuntematon korvaa merkkijonon "menete" merkkijonolla "menette", ja kaikki on hyvin.

s///-operaattorille annetaan korvattava regex ja millä se korvataan oletuksena se korvaa muuttujassa $_ olevan merkkijonon, mutta sille voi antaa myös toisen merkkijonon erityisellä "sidontaoperaattorilla" (=~).

#!/usr/bin/perl -w
use strict;

$\ = "\n";
$_ = "testausmerkkijono";
my $toinen = "toinenmerkkijono";

# löytyykö oletusmuuttujasta ($_) sana "testaus"
# m// voidaan lyhentää //
if( /testaus/ ) {

    # s/// voi olla myös s###, TMTOWTDI
    s#jono##;
    print "Löytyy: $_";
    
    # käytetään sidontaoperaattoria ja
    # korvataan "toinen" sanalla "kolmas"
    $toinen =~ s/toinen/kolmas/;
    
    print "\$toinen=$toinen";
}

Lisää asiasta Säännölliset lausekkeet Perlissä

Tiedostonkäsittely

Tiedosto avataan open-funktiolla. Parametrit:

open kahva, tiedostonimi
open kahva, moodi, tiedostonimi

Moodi voi olla joku seuraavista:

<  - Luetaan tiedostoa
>  - Tyhjennetään ja kirjoitetaan tai luodaan tiedosto
>> - Kirjoitetaan tiedoston loppuun tai luodaan tiedosto

testi.pl:

#!/usr/bin/perl -w
use strict;

# avataan tiedosto testi.pl ja sijoitetaan tiedostokahva 
# muttujaan $h
open my $h, "testi.pl" or die "Ei voi avata tiedostoa!";

# luetaan rivit taulukkoon @rivit
my @rivit = <$h>;

# käydään taulukon alkiot läpi ja tulostetaan rivit
for(@rivit) {
    print $_;
}

# tämä on sama kuin edellinen
print for(@rivit);

Tässä tiedosto avataan lukemista varten, jos avaaminen ei onnistu niin kuollaan die-funktiolla. Sitten luetaan rivit tiedostokahvasta @rivit-taulukkoon, jonka jälkeen käydään rivit läpi for-silmukassa ja tulostetaan ne.

Aikaisemmin tiedostokahvassa on käytetty ISOILLA kirjoitettua nimeä, joka ei alkanut $-merkillä. Jos käytetään -w optiota tai use warnings-pragmaa niin se varoittaa: "Unquoted string "h" may clash with future reserved word at testi.pl line 6.".

Jos tiedosto on isokokoinen, ei ole järkevää lukea koko tiedostoa taulukkoon. Silloin voidaan käydä silmukassa tiedosto läpi ja tehdä tarvittavat toimenpiteet.

#!/usr/bin/perl -w
use strict;

# avataan tiedosto testi.pl ja sijoitetaan tiedostokahva 
# muttujaan $h
open my $h, "testi.pl" or die "Ei voi avata tiedostoa!";

# käydään taulukon alkiot läpi ja tulostetaan rivit
for(<$h>) {
    # tulostetaan rivit, jotka alkavat #-merkillä
    print if(/^#/);
}

Tiedostoon voi kirjoittaa print-funktiolla. Syntaksi on vähän outo totuttuun verrattuna: print kahva lista. Eli kahvan ja listan väliin ei tule pilkkua. Tämä täytyy muistaa tai ohjelma ei toimi kuten sen pitäisi. Tiedosto suljetaan close-funktiolla.

#!/usr/bin/perl -w
use strict;

# avataan tiedosto kommentit.txt ja testi.pl
open my $kommentit, '>', "kommentit.txt" or die "Ei voi avata tiedostoa: $!";
open my $luettava, "testi.pl"            or die "Ei voi avata tiedostoa: $!";

# käydään taulukon alkiot läpi ja tulostetaan rivit
for(<$luettava>) {
    # tulostetaan kommentit.txt-tiedostoon 
    # rivit, jotka alkavat #-merkillä
    print $kommentit $_ if(/^#/);
}

close $kommentit;
close $luettava;

Perlissä voit käyttää myös muutamia valmiiksi määriteltyjä tiedostovirtoja, kuten STDOUT, STDERR ja STDIN.

#!/usr/bin/perl -w
use strict;

# avataan tiedosto stdout.txt
open my $stdoutfile, '>', "stdout.txt" or die "Ei voi avata tiedostoa: $!";

my $foo;

# suljetaan STDOUT
close STDOUT;

# avataan STDOUT niin, että tulostus menee $foo -muuttujaan
open STDOUT, '>', \$foo or die "Ei voi avata STDOUTia: $!";

# print-funktion tulostus menee oletuksena STDOUTiin
print "tulostetaan tekstiä stdoutiin!\n";

# tulostetaan STDOUTiin tulostettu teksti tiedostoon
print $stdoutfile "$foo\n";

# nyt stdout.txt sisältää
# "tulostetaan tekstiÀ stdoutiin!"

Tiedoston tila

Tiedoston tilaa voi tutkia '-'-alkuisilla operaattoreilla. Operaattori on jokin näistä: "-r-w-x-o-R-W-X-O-e-z-s-f-d-l-p-S-b-c-t-u-g-k-T-B-M-A-C".

-e	Tiedosto on olemassa
-z	Tiedosto on tyhjä
-s	Palauttaa tiedoston koon
-f	Tiedosto on selväkielinen
-d	Tiedosto on hakemisto
-l	tiedosto on symbolinen linkki
-p	Tiedosto tai tiedostokahva on putki (pipe)
-S	Tiedosto on soketti
-b	Tiedosto on erityinen
-c	File is a character special file. (?)
-t	Tiedostokahva on avattu tty:hyn
-u	setuid määritetty
-g	setgid määritetty
-k	Sticky bit asetettu
-T	Tiedosto on ASCII-muodossa (heuristinen arvaus).
-B	Binääritiedosto (-T:n vastakohta).

(lisää loput, [1])

Seuraava koodi tulostaa tämän näköisen merkkijonon: "Tiedosto ./testi.pl on 714 tavun kokoinen, se on tekstitiedosto ja se on suoritettava."

#!/usr/bin/perl -w
use strict;
 
# $file on sama, kuin tämän tiedoston nimi
my $file = $0;
 
# onko tiedosto olemassa
if(-e $file) {
    # onko tiedosto tyhjä
    if(-z $file) {
        print "Tiedosto on tyhjä\n";
    } else {
        # tiedoston koko
        my $size = -s $file;
 
        my $output = "Tiedosto $file on $size tavun kokoinen, se on ";
 
        if(-T $file) {
            print $output . "tekstitiedosto";
        } else {
            print $output . "binääritiedosto";
        }
        if(-x $file) {
            print " ja se on suoritettava.\n";
        } else {
            print " ja se ei ole suoritettava.\n";
        }
    }
} else {
    print "Tiedostoa $file ei ole olemassa\n";
}

Tehtäviä

  1. Kirjoita ohjelma, joka kysyy käyttäjältä nimen ja puhelinnumeron ja tallettaa nämä tiedostoon, jokaisen tiedostoon kirjoittavan väliin tulee ############-rivi, joka erottaa ihmiset toisistaan jos oikein tahdot snobbailla, käytä assosiatiivista taulukkoa
  2. Kirjoita ohjelma, joka lukee tiedostosta rivejä ja ilmoittaa millä rivillä (numero sekä rivin sisältö)on eniten tekstiä
  3. Muuta edellistä ohjelmaa sellaiseksi joka ilmoittaa sen rivin, jossa on eniten yksittäisiä sanoja
  4. Tee ohjelma, joka lukee tiedostosta kokonaislukuja pilkulla erotettuna ja laskee ne yhteen.

Erityismuuttujat

$_
On oletuksena monissa funktioissa, jos parametrejä ei ole annettu. Esimerkiksi chomp($_); ja chomp; tekevät saman.
@_
Taulukko sisältää funktion parametrit, joita voi käyttää suoraan $_[n]-merkinnän avulla, jossa n - 1 on parametrin numero.
@ARGV
Taulukko sisältää ohjelmalle annetut parametrit
$0
Sisältää ohjelman nimen
$1, $2, $3 ...
Sisältää säännöllisessä lausekkeessa etsityt ryhmät. Jos etsitään m/^(foo(bar)\d)/, niin $1 sisältää "foobar[num]" ja $2 "bar"
$.
Viimeisimmän tiedostokahvan rivinumero, jota on käytetty read, seek tai tell-funktioilla.
$@
Sisältää mahdollisen syntax errorin. Se on undef, jos edellinen eval-lohko suoritettiin ilman virheitä.
%SIG
Käytetään erilaisten käsitteijöiden lisäämiseen eri signaaleille. Voit asettaa käsittelijän keskeytykselle (SIGINT) näin: $SIG{INT} = sub { die "SIGINT"; };. Kun keskeytät ohjelman (Ctrl+C) se tulostaa "SIGINT at ./testi.pl line 4."
%ENV
Assosiatiivinen taulukko, joka sisältää ympäristömuuttujat.

$/, $\ </dt>
$/ muuttujaan asetetaan lukuerotin, joka normaalisti on "\n", eli luetaan rivi kerrallaan. $\ muuttuja sisältää tulostuserottimen, eli jos $\ = "\n", niin kun print:llä tulostetaan niin loppuun tulostuu rivinvaihto.

#!/usr/bin/perl -w
use strict;

$/ = " ";
$\ = "\n";

open my $luettava, "testi.pl" or die "Ei voi avata tiedostoa: $!";

# normaalisti luetaan rivi kerrallaan
# nyt luetaan sana kerrallaan
for (<$luettava>) {
    # poistetaan rivinvaihdot
    s/\n//g;

    # tulostaa myös rivinvaihdon
    print "[$_]";
}

</dd>

$$
PID
$<
UID
$^O
Käyttöjärjestelmä, esimerkiksi "linux".

TODO: lisää loput

Artikkelit

Linkkejä

Henkilökohtaiset työkalut