Till Startsidan
JavaScript.nu / Perl-kurs / Sökning i strängar, regular expressions

LÄR DIG ATT PROGRAMMERA PERL
Sökning i strängar, regular expressions

Äntligen! Efter en massa läsande har du nu tagit dig till de absolut kraftfullaste delarna av vad Perl har att bjuda - sökning och modifiering (modifieringen kommer dock först i nästa kapitel).

Det som gör Perl så överlägset många andra språk vid CGI-programmering är de väldigt kraftfulla verktyg som är inbyggda i Perl som används vid sökning och modifiering av strängar.
Under denna kurs kommer vi inte att lära oss varje liten möjlighet Perl har att erbjuda inom "sök & ersätt"-funktionerna, ty det skulle ta på tok för lång tid. Istället kommer vi att fokusera oss på de viktigaste och mest elementära delarna av dessa områden.

Vi börjar med en lätt visning av hur man kan kontrollera om en variabel innehåller en viss text. I vårt fall vill vi kolla om en sträng innehåller ett snabel-a (@):

#!/usr/bin/perl
print "Content-type:text/html\n\n";

$email="user\@mail.com";

if ($email =~ /\@/)
{
print "Bra, denna adress ($email) är OK.";
}
else
{
print "Din e-mail innehåller inget snabel-a.";
}

Utmatning:
Bra, denna adress (user@mail.com) är OK.
Viktigt att komma ihåg är att backslashet (\) framför snabel-a:et endast är där för att man annars hade fått ett felmeddelande. Ty ett snabel-a betyder ju att det som står därefter är en array. Vill man i en sträng använda ett @ måste man ha ett \ framför. Därför skriver man alltså \@, även när man avser ett vanligt @.

I vårt exempel är det enda nya att vi inom if-satsen har $email =~ /\@/. Denna rad säger oss:
Om ett @ ingår i strängen $email är uttrycket sant. Då körs print "Bra, denna adress ($email) är OK.";. I annat fall, dvs. om det inte finns ett @ i $email så är uttrycket falskt, då körs print "Din e-mail innehåller inget snabel-a.";.

Skulle vi istället för =~ använt !~ skulle vi få precis motsatt resultat. Då skulle uttrycket vara sant om @ inte fanns i $email och det skulle ha varit falskt om @ fanns i $email.

Förutom att man på detta sätt kan söka genom en sträng efter ett tecken eller en sträng, så kan man också ange villkor för vad man vill söka efter. Vårt e-mail-test ovan kollade t.ex. endast att ett @ ingick i adressen. Skulle vi i $email ha skrivit a@a, @@@@, @hotmail.com eller kanske rent av bara ett @ så skulle vårt script trott att detta är korrekt.
Låt oss nu ställa följande krav på adressen (egentligen är våra krav fortfarande för låga, fast dessa får duga "tills vidare"):

  1. Den ska starta med ett eller flera tecken. (t.ex: webmaster, abc, ¤%/(/&, 123 etc.)
  2. Sedan ska ett @ finnas.
  3. Sedan ska ett eller flera tecken finnas (t.ex. hotmail, usa, yahoo etc.)
  4. Sedan ska en punkt finnas.
  5. Sedan ska två eller tre tecken finnas (t.ex. nu, com, net, org etc.)
Vi börjar som vanligt med att visa exemplet för att sedan kommentera det:
#!/usr/bin/perl
print "Content-type:text/html\n\n";

$email="user\@mail.com";

if ($email =~ /.+\@.+\....?$/)
{
print "Bra, denna adress ($email) är OK.";
}
else
{
print "Din e-mail innehåller inget snabel-a.";
}

Utmatning:
Bra, denna adress (user@mail.com) är OK.
Har du aldrig sett detta tidigare tycker du nog att if-raden ser helt konstig ut. .+\@.+\....?$ är faktiskt inte bara några slumpmässigt valda tecken som satts in, utan dessa 13 tecken definierar vad vi nyss försökte beskriva med 5 rader. Detta är som du ser ett ytterst kraftfullt verktyg hos Perl att man kan, med endast ett fåtal tecken, tala om för scriptet vad man vill.
Låt oss nu ställa oss frågan, vad är egentligen .+\@.+\....?$?
Ok, för att påminna dig vad du tidigare lärt dig:
Har du ett uttryck som $email =~ /x/ så är detta sant om tecknet x finns i strängen $email.
Har vi t.ex. uttrycket $email =~ /abc/ så är detta sant om tecknen abc finns i strängen $email. Ett exempel förklarar lite tydligare hur det fungerar:
$email =~ /abc/ är sant för dessa värden på $email:
abc
aaabccc
sahkj 5abcdji36ab  e4ye
abcaidoaabc

$email =~ /abc/ är inte sant för dessa värden på $email:
abbc
aacab
aAbCc
ABC
Nu är det finurliga att vi inte bara behöver ha vanliga tecken som vi har haft då vi använt x, abc och \@ (åter en påminnelse, när vi letat efter \@ är det egentligen endast "@" vi letat efter, inte "backslash följt av @"), utan vi kan ha "specialtecken" som symboliserar en rad av olika tecken.
.+\@.+\....?$ är alltså en rad specialtecken som motsvarar de fem kraven vi tidigare ställt. Nedan går jag genom kraven en för en och förklarar vad varje del gör:
  1. Den ska starta med ett eller flera tecken. (t.ex: webmaster, abc, ¤%/(/&, 123 etc.):
    .+ ==> Egentligen betyder . "valfritt tecken". + betyder att det ska finnas ett eller flera av det tecken som detta tecken föregicks av (i vårt fall punkten, som alltså är "valfritt tecken").
    Summan av kardemumman blir alltså att först ska ett eller flera av "valfritt tecken" finnas.
  2. Sedan ska ett @ finnas.
    \@ ==> Detta har vi redan gått igenom. Detta betyder att här ska ett @ finnas.
  3. Sedan ska ett eller flera tecken finnas (t.ex. hotmail, usa, yahoo etc.)
    .+ ==> Detta har vi redan gått igenom i steg ett.
    Så åter igen: ett eller flera av "valfritt tecken" ska finnas.
  4. Sedan ska en punkt finnas.
    \. ==> Kom ihåg vad jag nyss sa att bara en punkt (.) betyder. Det betyder "valfritt tecken". Menar vi "bara en vanlig punkt" måste vi ha backslash före punkten (precis som på vårt snabel-a).
    Då förstår scriptet att vi menar "bara en vanlig punkt".
    Alltså betyder detta att en punkt ska finnas.
  5. Sedan ska två eller tre tecken finnas (t.ex. nu, com, net, org etc.)
    Vi delar nu in ...?$ i tre delar:
    .. ==> Först har vi två punkter. Dessa betyder (som du redan vet) att två "valfria tecken" ska finnas.
    .? ==> NU finns en punkt här, fast som du ser följs den av ett frågetecken, vilket betyder att "noll eller ett" av föregående tecken avses (jämför detta med t.ex. plus (+) som betyder "ett eller flera" av föregående tecken avses).
    I vårt fall betyder detta alltså att noll eller ett av "valfritt tecken" ska finnas.
    $ ==> Detta betyder att här ska strängen sluta.
Sätter jag nu ihåg mina understrukna meningar får jag, precis som våra krav var:
Understruken text					Strängen, bit för bit
ett eller flera av "valfritt tecken"			user
ett @						@
ett eller flera av "valfritt tecken"			mail
en punkt						.
två "valfria tecken"				co
noll eller ett av "valfritt tecken"			m
här ska strängen sluta					(strängen är slut här)
Nu undrar du säkert, hur sjutton ska jag minnas alla specialtecken? Punkter, asterixer, frågetecken etc.
Precis som du en gång i tiden lärde dig <HTML>, <BODY>, <BR> etc. kommer du lära att lära dig detta, fast tills dess, ha denna tabell som en referens (för de som vill bookmarka denna sida för tabellens skull så har jag även tänkt på dem):
Tecken Vad det symboliserar Exempel
. Ett enstaka tecken "Ja.a" matchar "java", "jaaa", "ja a" etc.
(Förklaring: j-a, valfritt tecken, a)
* Noll eller flera av föregående tecken "dit*" matchar "di", "dit", "ditt" etc.
(Förklaring: d-i, noll eller flera t)

"as.*k" matchar "ask", "astronomisk" etc.
(Förklaring: a-s, noll eller flera av valfria tecken, k)

"..a.*" matchar "alarm", "a-lag", "ana" etc.
(Förklaring: valfritt tecken, valfritt tecken, a, noll eller flera valfria tecken)

+ Ett eller flera av föregående tecken "fet+" matchar "fet", "fett", "fettt" etc.
(Förklaring: f-e, ett eller flera t)

"hop+" matchar "hop", "hopp" etc.
(Förklaring: h-o, ett eller flera p)

"storbrit+an+ien" matchar "storbritanien", "storbritannien", "storbrittannien" etc.
(Förklaring: s-t-o-r-b-r-i, ett eller flera t, a, ett eller flera n, i-e-n)

? Noll eller ett av föregående tecken "hejs?a?n?" matchar "hej", "hejsan", "heja" etc.
(Förklaring: h-e-j, noll eller ett s, noll eller ett a, noll eller ett n)

"katt.?.?" matchar "katt", "katter", "katten" etc.
(Förklaring: k-a-t-t, noll eller ett av valfritt tecken, noll eller ett av valfritt tecken)

"tal?" matchar "ta" och "tal".
(Förklaring: t-a, noll eller ett l)

() Gruppering av flera strängar "(sommar|vinter)" matchar "sommar" och "vinter".
(Förklaring: sommar eller vinter)

"user: (anna|berta|ceasar)" matchar "user: anna", "user: berta" och "user: ceasar".
(Förklaring: u-s-e-r-:-<mellanrum>, anna eller berta eller ceasar)

[] Ett tecken från listan "r[aeiouåäö]d" matchar "röd", "rad", "rit" etc.
(Förklaring: r, en vokal, d)

"r[aeiouåäö]+d" matchar "råd" (plus alla ovan), "road", "ruuud" etc.
(Förklaring: r, en eller flera vokaler, d)

"rus[ahk]" matchar "rusa", "rush" och "rusk".
(Förklaring: r-u-s, något tecken från listan)

[^] Ett tecken som inte finns i listan "[^aeiouåäö]a.*an" matchar "badlakan", jaktplan", "marsipan" etc.
(Förklaring: icke-vokal, a, noll eller flera av valfritt tecken, a-n)

"[^aeiouåäö]+[aeiouåäö]+" matchar "dö", "sko", "lie" etc.
(Förklaring: en eller flera icke-vokaler, en eller flera vokaler)

{} Det föregående tecknet ska finnas med ett visst antal gånger "{2}" betyder att det föregående tecknet ska finnas två gånger.
"{2,}" betyder att det föregående tecknet ska finnas minst två gånger.
"{2,6}" betyder att det föregående tecknet ska finnas två till sex gånger.

".{3}" matchar "abc", "1*4", "-A-" etc.
(Förklaring: tre valfria tecken)

"[askt]{4,}" matchar "satt", "katts", "kast" etc.
(Förklaring: fyra eller fler tecken från listan)

"hit{1,2}" matchar "hit" och "hitt".
(Förklaring: h-i, ett till två t)

Som nybörjare kommer du nog att se att en sådan här tabell är ovärderlig när du ska använda dig av sökning framöver.
En sak du ska tänka på är att en punkt (.) inte matchar radbyten (\n). Vill du ha ett "tecken" som matchar ["valfritt tecken" eller "radbyte"] så måste du använda dig av parenteser, dvs. (.|\n).

Det finns vissa teckenuppsättning som är extra vanliga i programmering. För dessa finns speciella escape:ade tecken (tecken som har ett backslash innan, t.ex: \@) som man kan använda. Dessa visas i tabellen nedan:
\d Ett nummer [0-9]
\D Inte ett nummer [^0-9]
\w Ett alfanumeriskt tal [a-zA-Z0-9_]
\W Inte ett alfanumeriskt tal [^a-zA-Z0-9_]
\s Någon form av mellanrum [ \t\n\r\f]
\S Inte någon form av mellanrum [^ \t\n\r\f]

Andra tecken som kan användas visas nedan. De tre första - tab, newline och return - är de du bör memorera. De andra kommer du inte stöta på allt för ofta.

	\t		tab		(HT, TAB)
	\n		newline		(NL)
	\r		return		(CR)
	\f		form feed		(FF)
	\b		backspace		(BS)
	\a		alarm (bell)	(BEL)
	\e		escape		(ESC)
	\033		octal char
	\x1b		hex char
	\c[		control char
Övrigt bra att kunna:
	^		Tecknet som markerar början av datasträng
	$		Tecknet som markerar slutet av datasträng
	\l		Om nästkommande tecken är en stor bokstav, gör denna till en liten
	\u		Om nästkommande tecken är en liten bokstav, gör denna till en stor
	\L		Alla tecken fram till \E blir små
	\U		Alla tecken fram till \E blir stora
	\E		Avslutar samtliga \L och \U som påbörjats
Slutligen vill jag bara påminna om att alla sökningar tar skillnad på små och STORA bokstäver. "Abc" är inte samma sak som "abc". För att bli kvitt detta "problem", lägg till ett "i" efter det andra slashet. Dvs, istället för denna rad...
if ($strang =~ /abc/)
...så ska du ha denna rad...
if ($strang =~ /abc/i)
...Om du vill att $strang ska sökas utan att man skiljer mellan STORA och små bokstäver.

[Perl guiden] - [Till kapitel 12]






Copyright © Omid Rouhani 1997-2022; Alla rättigheter reserverade.
Guider: [ HTML guide ] - [ JavaScript guide ] - [ DHTML guide ] - [ Perl guide ] - [ Sitemap ]