<< Tilbage IndholdRegulære udtryk Hvad er det? Første eksempel Introduktion til metacharacters ^ Starten af en streng $ Slutningen af en streng | Alternation (det ene eller det andet) [] Character classes [^ Negated character classes . Punktum \ Backslashes Quantifiers * Stjernen + Plus ? Spørgsmåltegn {} Tuborgklammer Forkortelser Opsummering Fang indhold med parenteser Php's regex funktioner Preg_match Preg_replace Avanceret regex Søg case-insensitive /e-modifieren Regulære udtrykHvad er det?Regulære udtryk (regular expressions eller regex), er ekstremt nyttige når man taler om validering. Validering vil sige at man kontrollere at de informationer man modtager er gyldige. F.eks. om email-adresser, telefonnumre, datoer, urls er gyldige. Man kan altså bl.a. bruge det til at undersøge om strenge har et bestemt format/form på en meget fleksibel måde. Derudover kan man hive komplekse dele af en streng ud, eller erstatte dele med noget andet. Der findes mange forskellige varianter af regulære udtryk. I denne tutorial benytter vi os af perl-kompatible udtryk (PCRE), som er det mest udbredte. I PHP giver det mulighed for bl.a. at benytte funktionerne preg_match() og preg_replace().Første eksempelVi starter ud med et simpelt eksempel:
/hejsa/
Denne regex matcher en streng der indeholder ordet hejsa. De 2 skråstreger kaldes delimiters og angiver i princippet bare hvor udtrykket starter og stopper. I stedet for skråstreger kunne jeg også have benyttet andre tegn (f.eks. #hejsa#), men det skal være det samme tegn der starter og slutter regex'en.
Det er vigtigt lige at huske på, at det regulære udtryk søger inde i en tekst (streng) hvor den forsøger at finde/matche noget der svarer til udtrykket. Ovenstående eksempel ville f.eks. matche 'blahh hejsa blahh'
Introduktion til metacharactersMetacharacters er tegn som har en bestemt betydning i et regulært udtryk. Det er disse tegn der gør regulære udtryk så kraftfulde, for hvis man bare ønsker at søge efter et ord i en streng, så er der meget simplere metoder til dette formål.Starten af en streng
/^hejsa/
Et ^ tegn betyder groft sagt "starten af strengen". Dvs. eksemplet ovenfor forsøger at matche en streng der starter med h, efterfulgt af e, j, s, og a. Det kunne eksempelvis være: hejsa hvordan går det. ^ er et metacharacter, og har altså en helt bestemt betydning, nemlig starten af strengen. Slutningen af en streng
/hejsa$/
Her er slutnigen af strengen angivet med et dollartegn (har intet med variabler at gøre som vi normalt bruger dollartegnet til i php). Eksemplet vil matche f.eks.: jamen hejsa og hejsa.
AlternationAlternation giver mulighed for at matche det ene eller det andet. Eksempel:
/^(hej|goddag|velkommen)/
Her matcher vi en streng der starter med enten hej eller goddag eller velkommen. De forskellige muligheder er adskilt med et | tegn. Både hejsa hvordan går det, goddag du og velkommen til min side vil kunne bruges.
Her er et eksempel mere hvor vi gerne vil finde ud af om strengen indeholder navnet Michael. Men Michael kan jo både staves med ch og k, og vi vil gerne kunne tillade begge:
/mi(ch|k)ael/
Bemærk hvordan vi bruger parentesen til at afgrænse.
Character classesMed en character class ([..]) kan man fortælle hvilke tegn/tal/bogstaver der er tilladte på en bestemt position i en streng. Eksempel:
/a[cbah]/
Her forsøger den at matche en streng der indeholder et a efterfulgt af et af de tegn som står i klammen (f.eks. ab, aa eller ah). Rent praktisk har ovenstående eksempel samme betydning som /a(c|b|a|h)/
Indholdet af klammen er altså de ting der tilladte på præcis den plads. En smart feature ved en character class er, at man kan benytte en sekvens (f.eks. fra 0 til 9 eller a til z). Eksempel:
/5[a-z0-9]/
Her matcher vi et 5 tal efterfulgt af et bogstav fra a til z eller et tal fra 0 til 9. Bemærk at den som standard søger case-sensitive, dvs. at a-z ikke tillader store bogstaver. Her er endnu et eksempel hvor vi både tillader store bogstaver, tal, samt de danske tegn æ, ø og å:
/^[a-zA-Z0-9æøåÆØÅ]/
(Matcher en streng der starter med et af de tegn vores character class tillader)
Negated character classesI afsnittet ovenover kiggede vi på hvordan man med en character class kan tillade bestemte tegn, på en bestemt plads. Men kan også angive hvilke tegn man IKKE ønsker. Dette gøres ved at tilføje et ^ tegn i starten af character klassen:
/^[^0-9]/
Matcher en streng der IKKE starter med et tal mellem 0 og 9. Bemærk at tegnet ^ udenfor klammerne betyder starten af strengen mens ^ indenfor klammerne fortæller hvilke ting vi ikke ønsker.
PunktumEt punktum er også et metacharacter, som man bruger til at matche hvilket som helst tegn med. Eksempel:
/^a.../
Her matcher vi en streng der starter med a efterfulgt af hvilket som helst tegn tre gange (og ikke kun a... men også a-B9, a123 osv.). Punktummet repræsenterer i princippet alt.
Backslashes fjerner betydningenVi har set på hvordan bestemte tegn har en helt bestemt betydning i et regulært udtryk. Men man kan selvfølgelig også komme ud for at skulle bruge disse tegn (f.eks. ".com" uden at punktummet betyder hvilket-som-helst-tegn). Der problem kan man løse ved at tilføje en backslash:
/\.dk$/
Her matcher vi en streng der slutter med ".dk". Bemærk at vi har tilføjet en backslash til punktummet, så den mister betydningen hvilket-som-helst-tegn. Dette kan man også gøre med alle andre metacharacters.
QuantifiersQuantifiers bruges til at bestemme hvor mange gange f.eks. et tal skal optræde. Der er grundlæggende set 4 metoder at gøre det på:StjernenMan bruger stjernen/asterisk til at matche noget bestemt 0 ellere flere gange. Eksempel:
/^[0-9]*/
Matcher et tal fra 0-9 så mange gange som muligt, i starten af en streng. Det kunne f.eks. være: '112' i strengen 112 er nummeret på alarmcentralen. Quantifiers (her stjernen) bruges altså til at bestemme hvor mange gange, at det der står foran skal optræde. PlusPlus (+) minder meget om stjernen, bortset fra at her skal det foranstående optræde minimum én gang. Eksempel:
/.+/
Her matcher vi en streng der indeholder hvilket som helst tegn (punktummet) 1 eller flere gange. Der kan i princippet være alle strenge, bare de ikke er tomme.Der er intet i vejen for at benytte en parentes foran en quantifier:
/([0-9] )+/
Matcher et tal efterfulgt af et mellem, én eller flere gange. Det kunne være '3 2 6 7 ' eller bare '1 '
SpørgsmålstegnNår man bruger spørgsmålstegnet skal det foranstående optræde 0 eller 1 gang. Eller rettere: optræder MÅSKE:
/([0-9] ?)+/
Et tal, måske efterfulgt af et mellemrum, 1 eller flere gange. Det kunne være: '123', '12 3' eller '1 2 3'
TuborgklammerMed tuborgklammer kan vi mere præcist angive hvor mange gange det foranstående skal optræde. Eksempel:
/^[0-9]{2,5}$/
Matcher en streng der starter med et tal, som optræder mellem 2 og 5 gange, og så slutter strengen. Det kunne være '12345', '12' eller '6421'.
Man kan også fortælle den at vi som minimum vil have det til at optræde et bestemt antal gange, uden noget øvre loft:
/^[0-9]{5,}$/
Matcher en streng der starter med et tal, der optræder 5 gange til uendelig, og så slutter strengen. Det kunne være '1234567897545' eller '98765'.
ForkortelserDer findes nogle smarte forkortelser man kan benytte. Her er en tabel med de mest nyttige:
OpsummeringHer er en lille opsumering på hvad vi har lært hidtil:
Fang indhold med parenteserEn af de ting der gør regulære udtryk så kraftfulde, er muligheden for at trække indhold ud af en streng, og ikke bare finde ud af om den matcher eller ej. Og det gør man ved at benytte parenteser omkring de ting man gerne vil have fat i. Forestil dig en streng der indeholder '#2=Jens Hansen' og vi så hive tallet ud, samt navnet. Dette kan man gøre på følgende måde:
/^#([0-9]+)=(.*)$/
To gange bruger vi en parentes. Først omkring tallet, [0-9]+, og dernæst omkring alt hvad der kommmer efter lighedstegnet. Det gør så at vi f.eks. vha. PHP kan få et array ud med indholdet af parenteserne (plads 1 indeholder tallet 2 og plads to indeholde navnet). Et eksempel mere... forestil dig at vi har en email-adresse 'test@testsiden.dk', og gerne vil trække det der står før snabel-a ud, og det der står efter:
/([^@]+)@(.+)/
[^@]+ betyder alt andet end et snabel-a, 1 eller flere gange. Det vil gå med t, e, s og t, men når den så kommer til @, så stopper den og går videre. Så kommer der et snabel-a, og bagefter hvilket som helst tegn, 1 eller flere gange. De to dele jeg ønsker at trække ud har jeg sat parentes omkring. Lige om lidt ser vi på hvordan det rent praktisk foregår med php. Php's regex funktionerIndtil nu har vi kigget på regulære udtryk generelt. Det begrænser sig på ingen måde til php, og kan derfor bruges i en lang række sprog. Nu skal vi se på hvordan man i php kan benytte sig af regulære udtryk.preg_match()preg_match() funktionen bruges, som navnet nok antyder, til at matche en streng mod et regulært udtryk. Eksempel:Kode:
Resultat: Strengen blev matchet, et gyldigt dansk postnummer Det første argument i funktionen indeholder selve det regulære udtryk, mens det andet argument indeholder den streng vi gerne vil kigge i. Funktionen returnerer true eller false afhængig af om det lykkedes. preg_match() kan også bruges til at trække data ud. Lad os prøve et af de tidligere eksempler med e-mail adressen: Kode:
Resultat: Strengen blev matchet, og indeholder følgende:
Læg mærke til at der er kommet et ekstra parameter på preg_match() funktionen. Det er $regs som kommer til at indeholde det vi har angivet i parenteserne. $regs[0] indeholder alt hvad der er blevet matchet, $regs[1] indeholder første parentes og $regs[2] anden parentes.
test@testsiden.dk test testsiden.dk preg_replace()Du har sikkert prøvet at skrive et link på et forum, hvorefter linket er blevet gjort klikbart. Det er højst sansynligt et regulært udtryk man har benyttet, hvor man erstatter selve linket med linket puttet ind i et a-tag. preg_replace() erstatter ét med noget andet, vha. et regulært udtryk, i en streng. Her er et eksempel hvor vi fremhæver alle tal i en streng:Kode:
Resultat: Jeg er 123 år gammel
Det første argument indeholder det regulære udtryk for hvad der skal erstattes, det næste argument hvad det skal ersattes til og det sidste argument hvori det skal ske. Læg mærke til at vi benytter \\0 til at få fat i indholdet af det udtrykket har matchet. Det fungerer lidt på samme måde som med parenteser. \\0 indeholder hele udtrykket, \\1 indeholder den første parentes osv. Her er et eksempel mere hvor vi benytter parenteser:
Kode:
Resultat: test@testsiden.dk
Den første parentes fanger det der står før snabel-a, og det erstatter vi med <i>\\1</i> hvor \\1 selvfølgelig svarer til indholdet af den første parentes. På samme måde gør vi det der står efter snabel-a fed.
Avanceret regexSøg case-insensitiveDet er ikke altid at man med sikkerhed kan sige, hvordan strengen man forsøger at matche er bygget op. Som standard er et regulært udtryk case-sensitive, dvs. der er forskel på store og små bogstaver. Forestil dig at du har en HTML kode hvor du vil finde ud af hvad titlen er (title tag'et). Det kan både være <title>test</title>, <TITLE>test</TITLE> og <TiTlE>test</TiTlE>. Derfor duer det ikke med /<title>([^<]*)<\/title>/. I stedet er det nødvendigt at tilføje en såkaldt modifier. Det er et bogstav man sætter efter den afsluttende delimiter (den sidste skråstreg). I dette tilfælde, hvor vi vil søge case-insensitivt, er det bogstavet 'i' vi skal have fat i. Eksempel:Kode:
Resultat: dette er min titel
Havde vi ikke sat det lille i-bogstav efter den sidst skråstreg, så havde udtrykket ikke matchet noget, da "title" ikke er det samme som "TiTlE".
/e-modifierenNormalt når man bruger preg_replace() til at erstatte, så erstatter vi et udtryk med en streng. e-modifieren giver mulighed for at erstatte et udtryk med en streng som bliver evalueret af php, med andre ord: vi kan bruge php kode. Det illustreres meget godt af følgende eksempel:Kode:
Resultat: Denne SIMPLIFICEREDE test viser e MODIFIEREN
I eksemplet erstattes ord på mindst 7 tegn med det samme ord bare i uppercase. Bemærk at den udføre det andet argument (strtoupper("\\1")) som PHP kode. Dette kan lade sig gøre ved brug af e-modifieren.
Der er visse ricisi forbundet ved at gøre det på denne måde, så brug det med omtanke (læs herunder).
|