<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <HTML> <HEAD> <LINK REL="StyleSheet" HREF="perlkurs.css" TYPE="text/css" MEDIA="screen"> <TITLE>Perlkurset, Høst'99</TITLE> <META NAME='version' CONTENT='1.96'> <META NAME='author' CONTENT='Salve J. Nilsen'> </HEAD><BODY BGCOLOR=white> <P><H1><FONT SIZE=+4>Perlkurset, Høsten '99</FONT></H1>I regi av Programvareverkstedets Faglige Forum</P> <HR><P><TABLE WIDTH=100%> <TR><TD WIDTH=80%><H2>Kursoversikt</H2> Kurset er beregnet for de som er kjent med grunnleggende programmering inkludert funksjoner, bibliotek og elementære objekt-orienteringsmetoder. Vi vil se på språkets sterke og svake sider, de viktigste grunnelementene samt mer avanserte ting som komplekse datastrukturer og objekt-orientert programmering. Vi skal også lage enkle og mer avanserte perl-script, bruke moduler og dokumentere på en enkel måte. Perl under Microsoft-plattformer blir gledelig ignorert - UNIX er tingen! :^)</TD><TD></TD></TR></TABLE></P> <A NAME='C1'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 1: Hva er Perl?</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Liten</H3> <CODE>perl -e 'print "Hello, World!\n";'</CODE> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Åpen</H3> "Practical Extraction and Report Language" er et fjerdegenerasjons språk som er laget for "å få jobben gjort." Språket er over ti år gammelt, og uvikles som et OSS-prosjekt av Larry Wall i samarbeid med flere hundre mennesker fra hele verden. Perl og de aller fleste modulene er lisensiert under "GNU Public License" eller "Artistic License" - du velger selv. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Kraftig</H3> Perl har flere GUI-moduler, støtter alle lavnivå internettprotokollene, har uhyre kraftige tekstbehandlings-muligheter, tillater både funksjonell og OO-programmering, har meget gode database-API, og tillater det meste noen skulle trenge å programmere i løpet av en dag. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>'Naturlig'</H3> Perl er fra begynnelsen av blitt utviklet som et "naturlig" språk - det vil si at det er så dynamisk at du kan gjøre nyttige ting selv om du bare kan noen få ord, eller at du kan bruke år på å mestre hele språket. Det er lett å lære seg nye elementer i språket, og det finnes altids en nåte å uttrykke seg på som passer din programmeringsstil. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Til fare for liv og helse!</H3> Dessverre er det for lett å programmere dårlig eller farlig i perl - slikt kommer ofte med på kjøpet når man velger å bruke et kraftig verktøy. Perl gir nok muligheter til at du ikke bare kan skyte deg selv i foten, men faktisk gjøre det med stil, ekstravaganse og utrolig letthet! Heldigvis har språket et par hjelpemidler så du unngår de groveste dumhetene. Det gir derimot ikke grunn til å la være å passe på! </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Litt større</H3> Om du vil, kan du også bryne deg på litt "vanskeligere" ting. (Denne er egentlig ikke så vanskelig! Etter kurset bør du kunne finne ut hva som skjer.) <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl # En obfuskert signaturfil? ($_='$ZNVYGB+$FWA?$CII:$BET;')?y:;ZA-Y\:?+${':\nm-za-l.@\:\0:?print:'}.':'.$'; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C2'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 2: Pathologically Eclectic Rubbish Lister</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hva egner perl seg til?</H3> <UL> <LI>Vanlige og uvanlige systemadministrasjonsoppgaver. </LI> <LI>Nettverkskommunikasjon. </LI> <LI>CGI-programmering. </LI> <LI>"Rapid Prototyping." </LI> <LI>"Lim" mellom applikasjoner. </LI> <LI>Effektiv behandling av store mengder tekst (HTML? XML? loggfiler?) </LI> </UL> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hva egner det seg ikke til?</H3> <UL> <LI>Svært store og/eller komplekse prosjekter. </LI> <LI>Arbeidsoppgaver der maskinressursene er knappe. </LI> <LI>Oppgaver det programmet krever svært rask utførelse og/eller høy responstid. </LI> </UL> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Men tenk over oppgaven!</H3> Det er mulig perl ikke er den beste løsningen til akkurat din oppgave! Det finnes mange språk, og vårt egner seg ikke til alt (selv om det kan brukes til svært mye.) Om et skriptspråk er løsningen, ta gjerne også en titt på Python, TCL, Scheme eller til og med Visual Basic - alle disse har egne fordeler og ulemper. Noen ganger trenger du ytelsen fra lavnivåspråk, og da er det meget mulig at Perl er feil løsning.... Kanskje det smarteste er å lage en perl-modul i C? :^) </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C3'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 3: Latskap, Utålmodighet og Hovmod!</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Perl-programmererens tre dyder</H3> <UL> <LI>Latskap, fordi du velger å skrive kode en gang, slik at det også kan brukes andre steder og av andre. Merk også at du dokumenterer skikkelig, for da slipper du å svare på dumme spørsmål fra folk som bruker koden din! </LI> <LI>Utålmodighet, fordi du ikke vil vente på datamaskinen hele tiden, og heller passer på at koden din ikke bare reagerer på behovene dine, men faktisk forutser dem! </LI> <LI>Hovmod, fordi det får deg til å skrive kode som andre ikke vil kritisere. </LI> </UL> Følg dem, og alt går så meget bedre! </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C4'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 4: Fordeler og Ulemper</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Plusspoeng</H3> <UL> <LI>Perl er et høynivå språk med tilgang på lavnivå kall om man trenger det. </LI> <LI>Å programmere i perl går fort - man kan få mye effekt ut av få linjer kode, noe som man kan oversette direkte til spart tid og penger. </LI> <LI>Perl har et rikt utvalg av moduler som omhandler alt fra kryptering og autentisering til verktøy som kan brukes i molekylærbiologi og til å samle e-postaadresser på USENET. (Ikke gjør det!) </LI> <LI>Perl har flere innebygde sikkerhetsfunksjoner, og et godt utvalg med moduler som gjør livet lettere. </LI> <LI>Det går an å "vokse" med språket, siden det er enkelt, kraftig og smidig. Det er alltid noe nytt du kan lære og et triks som gjør programmeringen morsommere. (Perl er en skrekk for språkminimalister.) </LI> </UL> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Minuspoeng</H3> <UL> <LI>Perl tar - og beholder - alt den trenger av ressurser. Det er ikke vanskelig å sluke alle ressursene på en maskin om man ikke passer på! </LI> <LI>Kildekoden i et perl-program kan lett gjøres uleselig! Prøv å søke etter "Obfuscated Perl contest" på nettet, og forbered deg på en stygg hodepine. </LI> <LI>Språket kan for enkelte være tungt å lære/bruke på grunn av mengden med "spesialvariabler." </LI> <LI>Perl er en skrekk for språkminimalister. (Det går an å "vokse" med språket, siden det er enkelt, kraftig og smidig. Det er alltid noe nytt du kan lære og et triks som gjør programmeringen morsommere.) </LI> <LI>Språket lærer deg ikke å programmere godt/pent - det må du gjøre selv! Ikke bli fristet til å skrive "bruk og kast-kode". </LI> </UL> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C5'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 5: Datastrukturer i Perl</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> I perl opererer man i hovedsak med tre typer data (det finnes flere, men de er ikke så viktige i starten.) <UL> <LI>"Scalar" - Et enkeltelement (tekst, tall, pekere, m.m.) - <CODE>$foo</CODE>. </LI> <LI>"Array" - En liste av enkeltelementer, med tall fra null og oppover som indeksverdier - <CODE>@bar</CODE>, <CODE>$bar[0]</CODE> eller <CODE>$bar[$tall]</CODE>. </LI> <LI>"Hash" - En liste med navngitte indeksverdier i stedet for tall ("Hashes" ogr også kjent som "Assosiative Arrays") - <CODE>%baz</CODE>, <CODE>$baz{tekst}</CODE> eller <CODE>$baz{$indeks}</CODE>. </LI> </UL> Variabler og datastrukturer trenger ikke å forhåndsdeklareres, men kan istedet opprettes når man trenger dem. Dette betyr ikke at det er dumt å deklarere dem på forånd! Faktisk, glem det jeg skrev om valgfri forhåndsdeklarering, og lat som om du må gjøre det! </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C6'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 6: Scalars (skalare verdier?)</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> Skalare verdier angis ved å bruke en '$' foran variabelnavnet. <CODE>$navn</CODE> vil angi at den enten er en streng, et tall eller en referanse. I alle tilfeller vil variabelen kun inneholde en eneste verdi. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $hilsen = 'heisann'; my $person = 'Per'; print "$hilsen, $person! Har du det bra?\n"; my( $svar, $tilstand ) = ( "joda", "bra" ); print "$svar, det går $tilstand.\n"; </PRE></FONT></TD></TR></TABLE><BR> I mange programmeringsspråk (f.eks. C eller Pascal) deklarerer man typen på variabelen (f.eks. "char* hilsen;") før den brukes, noe som ikke er nødvendig i perl - et tall er en skalar, og ikke en integer, float, double eller slikt. Bare husk å forhåndsdeklarere variablene (selv om du ikke må.) Dette kan gjøres ved å bruke <CODE>my()</CODE> foran variabelen, eller ved å deklarere dem globalt med <CODE>use vars ('$hilsen', '$person');</CODE>. Om du vil konkatenere strenger, kan du bruke "<CODE>.</CODE>" (punktum) mollom strengene. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $tid = scalar localtime; # hva gjør scalar() ? print "Vi fanget dette øyeblikket: " . $tid; </PRE></FONT></TD></TR></TABLE><BR> En viktig poeng: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $tekst = "foo"; print "Med doble fnutter: $tekst"; print 'Med enkle fnutter: $tekst'; # hva er forskjellen? </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C7'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 7: Arrays</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> En liste av "skalare verdier" indeksert med tall, der første indeksverdi er null. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my @array = ( "a", "b", "c", "d" ); print $array[1]; # Skriver ut "b" $array[2] = "foo"; print @array; # Skriver ut "afoocd" print "@array"; # Med resultat "a foo c d" </PRE></FONT></TD></TR></TABLE><BR> Det er verdt å merke seg at vi skriver ut et enkeltelement inni an array som <CODE>$array[1]</CODE> og ikke som <CODE>@array[1]</CODE>! Grunnen til dette er at vi vanligvis ønsker å få tak i en enkel verdi, og ikke en array! Om du absolutt må ha en array som resultat, kan du gjøre som så: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my @nok_en_array = @array[0,2]; print "@nok_en_array" # Vi får "a c" my @enda_en_array = @array[0..2]; print "@enda_en_array" # Skriver ut "a foo c" </PRE></FONT></TD></TR></TABLE><BR> Utover dette finnes det en del funksjoner som behandler "arrays", og er par av disse er: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> push(@array, "verdi2"); my $var1 = pop(@array); unshift(@array, "verdi2"); my $var2 = shift(@array); </PRE></FONT></TD></TR></TABLE><BR> Et eksempel uten videre dyp forklaring... <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my @array = ("a", "b", "c"); my $last = pop(@array); push(@array, "e"); my $first = shift(@array); unshift(@array, "d"); print @array; # Skriver ut "dbe" foreach my $verdier (@array) { print "$verdier\n"; } </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C8'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 8: Hashes (assosiative arrays?)</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> En assosiativ array, eller "hash", består av tilordnede nøkkel- og verdi-par hvor nøkkelen peker til en verdi: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my %hash = (key1 => 1, key2 => "tekst", key3 => 3); print $hash{key1}; # Skriver "1" </PRE></FONT></TD></TR></TABLE><BR> Merk at vi også her bruker '$' for å trekke ut en skalar verdi. For å gå igjennom alle verdiene i en hash så kan man bruke følgende prosedyre: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> foreach my $key (keys %hash) { print "$key => $hash{$key}\n"; } </PRE></FONT></TD></TR></TABLE><BR> Denne vil gå igjennom alle nøklene og verdiene for deretter å skrive dem ut. Nøkkelfunksjonen her er <CODE>keys</CODE> (pun intended), som returnerer alle nøklene i <CODE>%hash</CODE> (tilsvarende finnes det en en <CODE>values</CODE> funksjon). Man kan selvfølgelig utvide dette for å gjøre mer komplekse ting med hashen f.eks: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my %count_hash; foreach my $key (sort keys %hash) { # teller antall forekomster av bestemte verdier i en hash. ++$count_hash{$hash{$key}}; } </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C9'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 9: Subrutiner i perl</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> Bruk <CODE>my();</CODE>! Dette er spesielt viktig i funksjoner så variablene er unike for den navnerom de blir deklarert i. Godt tips som du allerede bør vite: Bruk aldri globale variabler! De skaper bare problemer. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> print pluss(7, 77); # Skriver ut "84" sub pluss { my( $argument1, $argument2 ) = @_; # Argumenter ligger i @_ return $argument1 + $argument2; } print pluss(4, 19); # Skriver ut "23" </PRE></FONT></TD></TR></TABLE><BR> Det er også likegyldig hvor i programemt vi definerer funksjonen - det er ditt ansvar å skrive ryddig kode! </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C10'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 10: Hvordan kjøre et perl-script</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> Følgende punkter må være i orden for at programmet skal kunne kjøre: <UL> <LI>Maskinen du logger inn på på ha perl installert! Dette kan du finne ut med <CODE>which perl</CODE>. </LI> <LI>Pass på at du har en ny versjon av perl. Dette kan du finne ut med <CODE>perl -v</CODE>. Versjon 5.004_04 eller nyere er bra, 5.003 eller nyere går an, og om du har noe eldre en det, oppgrader. Om du skulle være uheldig nok til å ha en versjon 4 perl, så bli kvitt den med en gang! Perl 4 er død, og vil aldri mere bli oppdatert! </LI> <LI>Lag en fil og plasser i toppen av fila. Første bokstav i fila skal være "#"! Strengt tatt er ikke <CODE>-wT</CODE>, <CODE>use strict;</CODE> og <CODE>use diagnostics;</CODE> nødvendig, men de er fryktelig nyttige å ha der mens du lager programmet - når du er ferdig kan du ta dem vekk igjen. </LI> </UL> <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -wT use strict; use diagnostics; </PRE></FONT></TD></TR></TABLE><BR> <UL> <LI>Pass på å erstatte <CODE>/usr/bin/perl</CODE> med resultatet til <CODE>which perl</CODE> om det er ulikt, ellers vil du ikke få kjørt programmet. </LI> <LI>Det er viktig at fila er eksekverbar! Dette fikser du med <CODE>chmod(1)</CODE> kommandoen. <CODE>man chmod</CODE> hjelper deg der om du ikke er kjent med kommandoen. </LI> </UL> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C11'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 11: Spesielle variabler</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> De "spesielle variablene." De er ofte sett på som det "mest ekle" ved perl, og det er de som tillater å skrive et program virkelig raskt - på godt og ondt. Du slipper ikke unna dem! En spesiell detalj ved disse, er at du ikke kan bruke <CODE>my();</CODE> for å gjøre dem til lokale variabler. Som oftest gjør ikke det noe, men om du f.eks. ønsker å endre an spesialvariabel inni en subrutine, uten at "orginalen" blir ødelagt, bruk <CODE>local();</CODE>. Merk at det finnes mange fler, men det er som oftest disse du vil møte først. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>@ARGV</H3> ...Er et predefinert array som inneholder kommandolinjeargumentene. Om du kjører perl-scriptet <CODE>test.pl</CODE> med parameter <CODE>"start"</CODE> vil argumentet bli plassert <CODE>$ARGV[0]</CODE> (og tilsvarede <CODE>$ARGV[1]</CODE> for det andre argumenter, osv.) </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>@_</H3> <CODE>@_</CODE> er et predefinert array som brukes til å gjøre argumentene til en funksjon tilgjengelig inni funksjonen. Dette vil si at alle subrutiner mottar argumentene sine i et array - noe som tillater en vilkårlig mengde parametere! <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> sub foo { print $_[1] } # Skriver ut andre argument i @_ foo("A", "B", "C"); # "B" blir skrevet ut! </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$_</H3> <CODE>$_</CODE> er meget spesiell. Dette er "default-variabelen"! Svært mange funksjoner i perl godtar å bli kjørt uten parametere i det hele tatt, eller uten å vise til hvilke variabler som blir behandlet. Når dette er tilfelle, vil alltid innholdet i <CODE>$_</CODE> bli brukt! <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> $_ = "En test\n"; print; # Skriver ut "En test\n" my @array = ( 1, 1, 2, 3, 5, 8, 13, 21 ); foreach ( @array ) { # Et og et element i @array blir plassert i $_ print; # ... og skrevet ut! } </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$!</H3> Denne variabelen inneholder feilmeldingsteksten til den siste feilen som oppstod. For eksempel om du prøver å åpne en fil for lesing, og feiler, vil årsaken til feilen stå der. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $filnavn = "/etc/passswd"; open( FIL, "<$filnavn" ) || die "Kan ikke lese fra '$filnavn': $!\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$0</H3> <CODE>$0</CODE> inneholder programnavnet. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>%ENV</H3> Inneholder miljøvariablene! Vil du vite hva $USER er satt til? <CODE>print $ENV{USER};</CODE>! </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$@</H3> Inneholder en eventuell feilmelding fra filsystemet om et system-kall har feilet. (Mere om <CODE>system()</CODE> kommer senere!) <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> system("ls -l", "/dev/nosuchthing", "/etc", "/usr"); die "Error: $@\n" if defined $@; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C12'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 12: Exterior: Dagobah -- day</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> With Yoda strapped to his back, Luke climbs up one of the many thick vines that grow in the swamp until he reaches the Dagobah statistics lab. Panting heavily, he continues his exercises -- grepping, installing new packages, logging in as root, and writing replacements for two-year-old shell scripts in Python. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Yoda:</H3> Code! Yes. A programmer's strength flows from code maintainability. But beware of Perl. Terse syntax... more than one way to do it... default variables. The dark side of code maintainability are they. Easily they flow, quick to join you when code you write. If once you start down the dark path, forever will it dominate your destiny, consume you it will. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Luke:</H3> Is Perl better than Python? </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Yoda:</H3> No... no... no. Quicker, easier, more seductive. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Luke:</H3> But how will I know why Python is better than Perl? </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Yoda:</H3> You will know. When your code you try to read six months from now. </P> <P CLASS='paragraph'> (Funnet på rec.humor.funny, og gjengitt uten tillatelse siden forfatter er ukjent. ;^) </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C13'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 13: Enda flere spesielle variabler</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Åh nei...</H3> Joda. Det finnes mange, og vi tar et par til som er kjekke å vite om. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$/</H3> <CODE>$/</CODE> kalles "the input record seperator", og bestemmer hva som skal være skilletegnet mellom hvert element su leser fra en filehandle. Standardverdi er <CODE>"\n"</CODE>, som medfører at man leser kun en linje om gangen. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> open( PASSWD, "/etc/passwd" ) || die "Kan ikke lese: $!"; my $line = <PASSWD>; print $line; # "navnsen:sEp4D.g/dg:6000:133:Etter Navnsen:/home/navnsen:/bin/false\n" local( $/ ) = ":"; my $field = <PASSWD>; close( PASSWD ); print $field; # "navnsdottir:" </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>$\</H3> "Output record seperator" er skilletegnet mellom hvert element i et array! Standardverdi er <CODE>""</CODE>, så det dukker ikke opp noe mellom hvert element. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my @stuff = qw( datamaskin sykkel dress bestikk ); print @stuff; # "datamaskinsykkeldressbestikk" local( $\ ) = " OG "; print @stuff; # "datamaskin OG sykkel OG dress OG bestikk" </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C14'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 14: Filbehandling</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hvordan leser man fra en fil?</H3> Pass på å sjekke returverdier, hva en du åpner! <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> open( FILE, "<fil.txt" ) || die "Kan'ke lese fila 'fil.txt': $!\n"; while ( <FILE> ) { # Gjør noe nyttig her. print; } close FILE || die "Kainn ittj' lukk fil.txt? $!\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hvordan skriver man til en fil?</H3> Sjekk av returverdi! Sjekk returverdi! <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> open( FILE, ">fil.txt" ) || die "Kan'ke skriv te 'fil.txt': $!\n"; print FILE "første linje\n"; close FILE || die "Kainn ittj' lukk fil.txt? $!\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C15'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 15: open()</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>En liten oversikt over hva open() kan gjøre</H3> Man bruker open til å kjøre klar filen for skriving eller lesing, og oppretter i prosessen en "filehandle" som man bruker under resten av behandlingen. I vårt tilfelle heter den FILE. Her kommer en liten oversikt over de forskjellige måtene å bruke <CODE>open</CODE> på: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> open(F, "fil"); # lesing open(F, "<fil"); # lesing -eksplisitt open(F, ">fil"); # skriving open(F, "+>fil"); # les og skriv open(F, ">>fil"); # tillegg (legge til på slutten) open(F, "|cmd"); # skriv til kommando open(F, "cmd|"); # les fra kommando open(F, "|-"); # skriv til fork open(F, "-|"); # les fra fork </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>The diamond operator</H3> En spesiell filehandle en "the diamond operator" <CODE><></CODE>. Om programmet ditt ikke tr noen argumenter vil <CODE><></CODE> lese fra STDIN. I motsatt tilfelle vil alle argumentene kunne tolkes som filnavn og automatisk leses inn. Det går ikke an å skrive til "the diamond operator". <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w # Et lite program som kommenterer ut hele filer. # use strict; while ( <> ) { print "# $_"; } </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C16'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 16: Betingelser og Kontrollstrukturer</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> Perl inneholder selvfølgelig de fleste kontrollstrukturene man har bruk for... <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w print "Skriv et tall: "; $tall = <STDIN>; chomp($tall); # fjerne linjeskift if ( $tall > 0 ) { print "positivt tall\n"; elsif ($tall < 0) { print "negativt tall\n"; } else { print "tallet er 0\n"; } </PRE></FONT></TD></TR></TABLE><BR> Forøvrig finnes det et par andre varianter av <CODE>if</CODE>-testen: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> unless ($tall == 2) { print "tallet er ikke 2"; } # Prøv "baklengs" notasjon! : print "God dag!\n" $natt && $a_menneske; # Eller hva med "kort-notasjonen"? my $tall = 0; print $tall ? "sann\n" : "usann\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C17'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 17: Logiske operatorer</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> Perl har to logiske operatorer, <CODE>&&</CODE> (AND) og <CODE>||</CODE> (OR). Begge er kortsluttende! dette betyr at "andre halvdel" ikke blir sjekket med mindre første halvdel er henholdscis sann (for AND) eller usann (for OR). I tillegg finnes <CODE>or</CODE> og <CODE>and</CODE>, men ikke bruk de, for de fungerer på en litt annerledes måte. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> $tall == 2 && print "tallet er 2\n"; $tall == 2 || print "tallet er ikke 2\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C18'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 18: Sannhetsverdier</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hva er sant?</H3> Vi snur heller på spørsmålet - Hva er usant? <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> print "Dette skal ikke skrives ut\n" if ("" || "0" || 0 || undef); </PRE></FONT></TD></TR></TABLE><BR> Alt annet tar perl som god fisk - om du fikk 1, "ingen" eller "-99" fisk vil perl være enig med deg. En liten detalj: perl tror deg dersom du sier du fikk "0.0" fisk! Dvs. "0.0" er sann... :) </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C19'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 19: Løkker</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>While og Until-løkker</H3> <CODE>while</CODE>-løkker blir kjørt såfremt startbetingelsen er møtt. I det startbetingelsen ikke lenger er sann vil programmet gå ut av løkken. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $tall = 0; while ($tall < 10) { $tall++; print "nå er løkken kjørt $tall ganger\n"; } </PRE></FONT></TD></TR></TABLE><BR> Løkker kan også skrives som ... <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> until( $event ) { # gjør noe her. } </PRE></FONT></TD></TR></TABLE><BR> ... som tilsvarer <CODE>while( ! $event )</CODE> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>For-løkker</H3> Denne bør være kjent. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> for( $i = 0; $i <= 10; $i++ ) { print $i; } </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C20'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 20: Kall på eksterne programmer</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>`backticks` og system()</H3> Ikke sjeldent vil det være interessant å starte opp eksterne programmer i et perl-script. For eksempel ønsker man å sende et e-brev, og starter sendmail for å gjøre dette, eller man vil ha en oversikt over hvilke prosesser som er i gang på maskinen. Det finne flere måter å gjøre dette på, og 'backticks' er en: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $tidspunkt = `date`; # Henter klokkeslett og dato fra date(1) # og legger den i $tidspunkt </PRE></FONT></TD></TR></TABLE><BR> Det er bakoverfnuttene (<CODE>``</CODE>) som forteller perl at den skal kjøre en system-kommando. Bakoverfnuttene fungerer også som vanlige fnutter, ved at variabler blir interpolert. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $foo = system("date"); # Skriver ut (!) dato, og setter $foo # til enten 0 eller et tall med statuskoder </PRE></FONT></TD></TR></TABLE><BR> Ta en titt på <CODE>perldoc -tf system</CODE> om du trenger å forstå returverdiene. </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>exec() - og open() igjen</H3> <CODE>exec()</CODE> gjør det samme som <CODE>system()</CODE> men den eneste forskjellen at perl-prosessen din ditt blir erstattet av programmet du <CODE>exec()</CODE>'er. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> exec( $program, "arg1", "arg2" ); </PRE></FONT></TD></TR></TABLE><BR> I tillegg kan man bruke <CODE>open()</CODE> som vi husker fra filbehandlingsdelen: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> open( LS, "ls|" ) || die "Kunne ikke åpne ls: $!\n"; </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C21'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 21: Faremomenter ved kall på eksterne programmer!</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hva kan gå galt?</H3> Gitt følgende uheldige scenario: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $argument = '/etc; rm -rf / >&- 2>&- &'; # Dette kan komme fra en ekstern kilde! kanskje du # leste inn parametere fra <STDIN>? system("ls -l $argument"); # Oops! </PRE></FONT></TD></TR></TABLE><BR> Ingen ønsker å oppleve dette - derfor er det viktig å passe på å lage perl-programmene sine skikkelige - SPESIELT HVIS ANDRE SKAL BRUKE DEM!! </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Hvordan unngå å drite seg ut?</H3> Et par gode triks er: <UL> <LI>Unngå å bruke <CODE>``</CODE>, <CODE>system()</CODE>, <CODE>exec()</CODE>, <CODE>open()</CODE>, <CODE>opendir()</CODE>, <CODE>syscall()</CODE>, <CODE>glob()</CODE> og andre funksjoner som aksesserer systemet. </LI> <LI>Bruk <CODE>-T</CODE> (taint-checking) som parameter til perl! </LI> <LI>Om du må bruke <CODE>system()</CODE> og tilsvarende funksjoner, pass på å bruke lister som argumenter i stedet for tekststrenger. Om du bruker en tekststreng for to eller flere ord sammen, så vil perl starte et eget skall for å "gjøre fornuft" av parameterene. <CODE>system("ls -l $dir1 $dir2")</CODE> er farlig, men <CODE>system("ls", "-l", $dir1, $dir2)</CODE> er OK. </LI> </UL> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C22'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 22: Regulære uttrykk (regular expressions)</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Perl sitt mest berømte våpen</H3> Regexp er perl sin største og mest populære styrke. Man kan med svært enkle konstuksjoner representere komplekse data. Regulære uttrykk blir oftest brukt til analyse, eller uthenting og endring av data i store mengde tekst. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w # use strict; while( my $logglinje = <> ) { print ++$teller,": $logglinje" if m/^mandag/; } </PRE></FONT></TD></TR></TABLE><BR> Her er kortversjonen av hva som er mulig med regulære uttrykk: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> bokstav matcher seg selv tall matcher seg selv \. matcher et punktum \tegn matcher et tegn \\ matcher \ . matcher alle tegn unntatt "\n" [abc] matcher a, b eller c [a-z] matcher a, b,... y, z [^abc] matcher alt unntatt a,b eller c \w [a-zA-Z0-9_] \W [^\w] \s matcher "whitespace" \S alt annet en whitespace \d [0-9] \D [^0-9] \n matcher newline \t matcher tab \b matcher begynnelsen eller slutten av et ord \032 matcher tegn tilsvarende oktalverdien gitt </PRE></FONT></TD></TR></TABLE><BR> For å enkelt lage kraftigere uttrykk trenger vi flere elementer ("Kvantifiserere"?). <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> * matcher 0 eller flere ganger + matcher 1 eller flere ganger ? matcher 1 eller 0 ganger {n} matcher nøyaktig n ganger {n,} matcher minst n ganger {n,m} matcher minst n og maks m ganger </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Grådige uttrykk</H3> I utgangspunktet er alle "Kvantifiserere" grådige - de ønsker å matche mest mulig, og om de få sjansen gjør de det. Det er ikke alltid vi er interessert i dette - noen ganger er vi f.eks. interessert i å få teksten mellom to apostrofer, men det er flere apostrofer på samme linje! For å unngå dette, kan vi legge til et spørsmålstegn etter "kvantifikatoren", så vil den prøve å matche minst mulig. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $test = '"hah" sa han. Hunden ytret et "voff!"'; $test =~ m/"(.*)"/; print $1; # Skriver ut 'hah!" sa han. Hunden ytret et "voff!' $test =~ m/"(.*?)"/; print $1; # Skriver ut '"hah!"' </PRE></FONT></TD></TR></TABLE><BR> Det går også an å legge til "ankre"! Hvis vi vet at en bestemt tekst er ved begynnelsen eller ved slutten av en linje, går det an å bruke. I tillegg bør du vite at man kan <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> ^ matcher begynnelsen av linjen $ matcher slutten av linjen </PRE></FONT></TD></TR></TABLE><BR> Og for å utføre en operasjon med regulære uttrykk, kan du gjøre. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w my @rest; while( <> ) { s/\r//g; # Fjerner ^M fra slutten av linja s/[æøåÆØÅ]/./g; # Erstatter alle æ, ø og å med punktum tr/a-z/A-Z/; # Gjør om små bokstaver til store m/(ab){2,4}/i; # matcher på abab (el.l.) uten å bry # seg om store eller små bokstaver push(@rest, $_); } my @foos = grep( ! /foo/i, @rest ); # vi trenger linjene uten "foo" </PRE></FONT></TD></TR></TABLE><BR> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Regexp-operatorer</H3> Du kan forandre hvordan et regulært uttrykk fungerer ved å legge til en eller flere operatorer etter uttrykket. De vanligste er <CODE>m//gimsx;</CODE> - det finnes fler, men de bryr vi oss ikke om nå. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> g Matcher uttrykket globalt i Ignorere store/små bokstaver m Behandle dataene over flere linjer s Behandle dataene som om de var på en linje x Ignorere "unescaped whitespace" - Gjør </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C23'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 23: Nøstede datastrukturer</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Referansemagi</H3> Nøstede datastrukturer, det vil si datastrukturer inni datastrukturer lager vi med hjelp av referanser. Eksempler kan være flerdimensjonelle arrays eller hasher av hasher. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my @array = ('foo', 'bar', ['a', 2, 'c'], {key1 => "verdi1", key2 => "verdi2"} ); </PRE></FONT></TD></TR></TABLE><BR> Her har vi en array som inneholder fire elementer. De to første er skalare, det tredje er en anonym array, og det fjerde en anonym hash. Gitt koden ovenfor, er følgende utsagn sanne: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> $array[0} == 'foo'; $array[2]->[1] == 2; $array[3]->{key2} == 'verdi2'; </PRE></FONT></TD></TR></TABLE><BR> Vi kan lage en referanse til <CODE>@array</CODE>, og om vi gjør det vil ting bli mer interessante. Gitt første uttrykk her, så er resten sanne: <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> my $aref = \@array; $aref->[1] == 'bar'; $aref->[3]->{key1} == 'verdi1'; </PRE></FONT></TD></TR></TABLE><BR> Alt dette kan kombineres hvordan du vil - bar husk å holde orden! </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C24'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 24: Moduler og 'package'</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>En enkel modul</H3> Prøv! Dette er ikke komplisert. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> # Vi starter med å lage en fil som vi kaller Hello.pm package Hello; # Samme navn som fila, men uten ".pm" # Om fila het Hello/World.pm, må vi kalle pakken Hello::World sub person { my $navn = shift; my $kjonn = shift; die "person() skal ha 2 argumenter" unless @_ == 0; die "$navn sitt kjønn må være 'M' eller 'K'! (ikke '$kjonn')\n" unless $kjonn =~ m/^[MK]$/; return [ $navn, $kjonn, 0 ]; # siste tallet er en "hilse-teller" } sub hils { my $person = shift; # vi venter oss returverdien fra person() my $hva = $person->[1] eq "M" ? "han" : "hun"; my $hvem = $person->[0]; $person->[2]++; # hvor mange ganger $person er blitt hilst på? print "Nei, se! Der har vi jo $hva $hvem!\n"; } sub vis_ant_hilsninger { my $person = shift; my $hvem = $person->[0]; my $ant = $person->[2]; print "Vi har hilset på $hvem $antall gang", ( $ant-1 ? "" : "er" ), "\n"; } 1; # det er viktig at alle moduler returnerer en sann verdi! </PRE></FONT></TD></TR></TABLE><BR> <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> # Ny fil! Dette er "hils.pl" package main; # Hoved-navnerommet heter "main", og trengs ikke å # annonseres på denne måten, egentlig. Med mindre vi # har flere "package" i samme fil... my $friend1 = Hello::person("Gorm", "M"); my @other_friends = ( Hello::person("Natalija", "M"), Hello::person("Remi", "M") ); # Og så hilser vi po et par venner :) Hello::hils( $friend ); Hello::hils( $other_friends[0] ); Hello::hils( $other_friends[1] ); Hello::hils( $friend ); Hello::hils( $other_friends[0] ); Hello::hils( $friend ); Hello::vis_ant_hilsninger( $friend ); Hello::vis_ant_hilsninger( $other_friends[0] ); Hello::vis_ant_hilsninger( $other_friends[1] ); __END__ Ferdig! Vi kunne ha fått penere kode ved å importere symbolene fra Hello.pm, men da mister vi fordelen av å vite nøyaktig hvilken pakke funksjonene hører til i. </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C25'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 25: OO-programmering</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Litt om hva som finnes</H3> Objekt-orientert programmering i perl er en litt pussig opplevelse. En del av OO-teorien er blitt droppet! - det finnes f.eks. ikke egne "public" eller "private" -egenskaper. Enkapsulasjon må programmereren selv sørge for å ikke bryte. Perl-objekter har likevel de viktigste elementene som modularitet, arv (også multippel arv, om vi trenger det), polymorfisme og annet. En klasse i perl lages ved å opprette en fil med en egen pakke i seg, og passe på at det finnes en konstruktor. Funkjonene i pakken er da metodene i klassen, globale variabler i pakkens navneromm bli klasse-variabler, og variablen konstrukoren returnerer blir objekt-variabler. Verre er det ikke! <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> # Vi vi prøver oss på nytt, og lager en fil som vi kaller Hello.pm package Hello; # Som før... sub new { # Vanlig navn på en konstruktor er "new" - ingen tvang! my $package = shift; # første argument er alltid en referanse # til my $navn = shift; my $kjonn = shift; die "new() skal ha 2 argumenter" if @_; die "$navn sitt kjønn må være 'M' eller 'K'! (ikke '$kjonn')\n" unless $kjonn =~ m/^[MK]$/; my $person = { navn => $navn, kjonn => $kjonn, _ant_hils => 0 }; bless( $person, $package ); # Her knytter vi $person til # $package, slik at vi får # effekten av en klasse. return $person; } sub hils { my $self = shift; my $hva = $self->{kjonn} eq "M" ? "han" : "hun"; my $hvem = $self->{navn}; $self->{_ant_hils}++; # hvor mange ganger "jeg" er blitt hilst på? return "Nei, se! Der har vi jo $hva $hvem!\n"; } sub vis_ant_hilsninger { my $self = shift; return $self->{_ant_hils}; } sub vis_navn { my $self = shift; return $self->{navn}; } sub vis_kjonn { my $self = shift; return $self->{kjonn}; } 1; # Så avslutter vi med en sann verdi. </PRE></FONT></TD></TR></TABLE><BR> <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w # Ny fil! Dette er "hils.pl" use strict; use diagnostics; use Hello; # Hello.pm må være tilgjegelig i @INC for at dette skal # fungere smertefritt. my $friend = Hello->new("Gorm", "M"); my @other_friends = ( Hello->new("Natalija", "M"), Hello->new("Remi", "M") ); # Og så hilser vi po et par venner :) print $friend->hils(); print $other_friends[0]->hils(); print $other_friends[1]->hils(); print $other_friends[1]->hils(); print $friend->hils(); print $other_friends[1]->hils(); print $other_friends[0]->hils(); print $friend->vis_ant_hilsninger(); print $other_friends[0]->vis_ant_hilsninger(); print $other_friends[1]->vis_ant_hilsninger(); __END__ </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C26'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 26: En CGI-modul</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>CGI_Lite</H3> En lett-versjon av den (mye) kraftigere CGI-modulen i perl - denne passer bedre til enkle oppgaver, og er ikke så tung for systemet. <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -wT # # Et enkelt CGI-script som returnerer data du har gitt. use strict; use diagnostics; use CGI_Lite; my $cgi = new CGI_Lite; # En annen måte å lage et objekt på $cgi->set_platform("Unix"); $cgi->add_mime_type("text/html"); my %form = $cgi->parse_form_data; # Hente inn data fra browser $/ = undef; # Vi vil ha alt på en gang når vi leser fra en filehandle my $page = <DATA> # Leser fra __DATA__ nedenfor foreach my $data_key (keys %form) { # Bytte ut f.eks. $NAVN med $form{NAVN} $page =~ s/\$$data_key/$form{$data_key}/gm; } $page =~ s/\$\w+/foo/gm; print "Content-type: text/html\r\n\r\n"; print $page; __DATA__ <HTML> <HEAD><TITLE>CGI_Lite-test</TITLE></HEAD> <BODY> <H1>Hei, $NAVN</H1> Du er $ALDER gammel, har jeg hørt! <HR> <FORM METHOD="POST" ACTION="$SCRIPT_URL"> Navn: <INPUT TYPE="text" NAME="NAVN" VALUE="$NAVN"><BR> Alder: <INPUT TYPE="text" NAME="ALDER" VALUE="$ALDER"><BR> <INPUT TYPE="submit"> </FORM> </BODY> </HTML> </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C27'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 27: Referanser</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Nyttige linker</H3> <UL> <LI>Kurssidene til PVV - <A HREF='http://www.pvv.ntnu.no/kurs/'>http://www.pvv.ntnu.no/kurs/</A> </LI> <LI>Perl.com - Hovedressursern for perl-informasjon på nettet. Her kan du søke i dokumentasjon, følge diskusjoner, lese artikler, få med deg perl-nyheter go mye mer - <A HREF='http://www.perl.com/'>http://www.perl.com/</A> </LI> <LI>CPAN - "Comprehensive Perl Archive Network" er et sentralt samlested for perl-moduler - <A HREF='http://www.perl.com/CPAN'>http://www.perl.com/CPAN</A> </LI> <LI>Perl Reference Topics - en meget bra oversikts-side over dokumentasjon - <A HREF='http://www.perl.com/reference/'>http://www.perl.com/reference/</A> </LI> <LI>comp.lang.perl.* - Nyhetsgrupper for perl-interesserte. Et par ukers "lurking" på disse kanalene er utrolig lærerikt! - <A HREF='news:comp.lang.perl.misc'>news:comp.lang.perl.misc</A> </LI> <LI>FMTEYEWTK - "Far More Than Everything You've Ever Wanted to Know About..." - <A HREF='http://www.perl.com/CPAN/doc/FMTEYEWTK/'>http://www.perl.com/CPAN/doc/FMTEYEWTK/</A> </LI> <LI>"The GNU Public License" - <A HREF='http://www.opensource.org/licenses/gpl-license.html'>http://www.opensource.org/licenses/gpl-license.html</A> </LI> <LI>"The Artistic License" - <A HREF='http://www.opensource.org/licenses/artistic-license.html'>http://www.opensource.org/licenses/artistic-license.html</A> </LI> <LI>"How To Write Unmaintainable Code" - <A HREF='http://mindprod.com/unmain.html'>http://mindprod.com/unmain.html</A> </LI> </UL> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Online dokumentasjon</H3> <UL> <LI><CODE>perldoc</CODE> er perl sitt plattformuavhengige dokumentasjons-system - prøv å kjøre <CODE>perldoc perl</CODE>! </LI> <LI>perldoc <UL> <LI>perl - For å få oversikten. </LI> <LI>perlstyle - Hvordanskrive ryddig kode. </LI> <LI>perlfaq - Mange spørsmål med gode svar! </LI> <LI>perldata - Datastrukturer </LI> <LI>perlre - Regulære uttrykk </LI> <LI>perlfunc - Funksjoner Extravaganza! </LI> <LI>perlrun - Hva kan du skrive på kommandolinja? </LI> <LI>perltoot - Et mini-kurs i Objekt-orientert perl! </LI> <LI>perlsec - Om sikkerhet, og hva du bør tenke på. </LI> <LI>perlpos - Hvordan lage enkel, profesjonell inline dokumentasjon. </LI> <LI>perlvar - Spesialvariabler... </LI> <LI>perltrap - Programmeringsfeller man kan gå i. </LI> <LI>perlmod - Hvordan man bruker moduler i perl. </LI> </UL> </LI> <LI>Prøv også <CODE>perldoc -tf funksjonsnavn</CODE>! </LI> </UL> </P> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Bøker</H3> <UL> <LI>"Learning Perl" - O'Reilly & Associates - ISBN: 1-56592-284-0 </LI> <LI>"Programming Perl" - O'Reilly & Associates - ISBN: 1-56592-149-6 </LI> <LI>"Perl Cookbook" - O'Reilly & Associates - ISBN: 1-56592-243-3 </LI> <LI>"Mastering Regular Expressions" - O'Reilly & Associates - ISBN: 1-56592-257-3 </LI> <LI>"Object Oriented Perl" - Manning Publications - ISBN: 1-88477-779-1 </LI> </UL> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C28'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 28: XML::Parser og XML::RSS</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>'Mine overskrifter'</H3> Scriptet, beskrivelse av det og eksempler på bruk kan du finne på <A HREF='http://www.webreference.com/perl/tutorial/8/'>http://www.webreference.com/perl/tutorial/8/</A> . <BR><TABLE CLASS="perlcode" BGCOLOR='#eeeeee' WIDTH=100% BORDER=1 CELLPADDING=5> <TR><TD CLASS="perlcode"><FONT SIZE=-1><PRE> #!/usr/bin/perl -w # rss2html - converts an RSS file to HTML # It take one argument, either a file on the local system, # or an HTTP URL like http://slashdot.org/slashdot.rdf # by Jonathan Eisenzopf. v1.0 19990901 # Copyright (c) 1999 internet.com Corp. All Rights Reserved. # See http://www.webreference.com/perl for more information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # INCLUDES use strict; use XML::RSS; use LWP::Simple; # Declare variables my $content; my $file; # MAIN # check for command-line argument die "Usage: rss2html.pl (<RSS file> | <URL>)\n" unless @ARGV == 1; # get the command-line argument my $arg = shift; # create new instance of XML::RSS my $rss = new XML::RSS; # argument is a URL if ($arg=~ /http:/i) { $content = get($arg); die "Could not retrieve $arg" unless $content; # parse the RSS content $rss->parse($content); # argument is a file } else { $file = $arg; die "File \"$file\" does't exist.\n" unless -e $file; # parse the RSS file $rss->parsefile($file); } # print the HTML channel print_html($rss); # SUBROUTINES sub print_html { my $rss = shift; print <<HTML; <TABLE BGCOLOR="#000000" BORDER="0" WIDTH="200"><TR><TD> <TABLE CELLSPACING="1" CELLPADDING="4" BGCOLOR="#FFFFFF" BORDER=0 WIDTH="100%"> <TR> <TD VALIGN="middle" ALIGN="center" BGCOLOR="#EEEEEE"><FONT COLOR="#000000" FACE="Arial,Helvetica"><B><A HREF="$rss->{'channel'}->{'link'}">$rss->{'channel'}->{'title'}</A> </B></FONT></TD></TR> <TR><TD> HTML # print channel image if ($rss->{'image'}->{'link'}) { print <<HTML; <CENTER> <P><A HREF="$rss->{'image'}->{'link'}"><IMG SRC="$rss->{'image'}->{'url'}" ALT="$rss->{'image'}->{'title'}" BORDER="0" HTML print " WIDTH=\"$rss->{'image'}->{'width'}\"" if $rss->{'image'}->{'width'}; print " HEIGHT=\"$rss->{'image'}->{'height'}\"" if $rss->{'image'}->{'height'}; print "></A></CENTER><P>\n"; } # print the channel items foreach my $item (@{$rss->{'items'}}) { next unless defined($item->{'title'}) && defined($item->{'link'}); print "<LI><A HREF=\"$item->{'link'}\">". "$item->{'title'}</A><BR>\n"; } # if there's a textinput element if ($rss->{'textinput'}->{'title'}) { print <<HTML; <FORM METHOD="GET" ACTION="$rss->{'textinput'}->{'link'}"> $rss->{'textinput'}->{'description'}<BR> <INPUT TYPE="text" NAME="$rss->{'textinput'}->{'name'}"><BR> <INPUT TYPE="submit" VALUE="$rss->{'textinput'}->{'title'}"> </FORM> HTML } # if there's a copyright element if ($rss->{'channel'}->{'copyright'}) { print <<HTML; <P><SUB>$rss->{'channel'}->{'copyright'}</SUB></P> HTML } print <<HTML; </TD> </TR> </TABLE> </TD></TR></TABLE> HTML } </PRE></FONT></TD></TR></TABLE><BR> </P> </TD><TD WIDTH=50%></TD></TABLE> <A NAME='C29'><P><TABLE WIDTH=80% BORDER=0> <TR><TH CELLPADDING=15 COLSPAN=2 BGCOLOR='#77eeff'><BR><HR SIZE=1 NOSHADE><FONT SIZE=+2>Del 29: Annet?</FONT><BR><HR SIZE=1 NOSHADE></TR> <TR><TD WIDTH=100%> <P CLASS='paragraph'> <H3 CLASS='paragraph'>Så kan man spørre...</H3> <CODE>perl -e 'print "Hva nå?\n";'</CODE> </P> </TD><TD WIDTH=50%></TD></TABLE> </HTML>