commit 75e7d0675f9cd070aed9f4e333c675d239875d42 Author: Kursmester Date: Wed Mar 5 11:17:00 2025 +0100 Recover from microbel diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ad509e --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Kurs i Perl og regex + +## Perl-kurs + +| | | +|-------|-----------------------------------------------------------------------------------------------| +| Tid: | Torsdag 7. september, fra 18:00 til 20:00 | +| Sted: | Auditorium R4, Realfagsbygget | +| Pris: | Kr 50 for ikke-medlemmer, gratis for medlemmer og ITEA-ansatte (PVV-medlemsskap koster kr 42) | + + +PVV arrangerer kurs i programmeringssprÃ¥ket Perl. Kurset er beregnet for folk som ikke har prøvd Perl før, men kan være nyttig for andre ogsÃ¥. Vi fokuserer pÃ¥ hvordan man kan lage enkle script, og pÃ¥ Ã¥ gi et grunnlag for Ã¥ lære seg mer selv. + +Kurset forutsetter litt programmeringserfaring, pÃ¥ nivÃ¥ med if-setninger, løkker og metodekall. + +Kursholder: Knut Auvor Grythe + +### Forrige Perl-kurs + +[Hjemmesiden til perl-kurset som var 2004-10-28](https://git.pvv.ntnu.no/Kurs/2004-perl). Her finner du foiler. + +## Regex-kurs + +| | | +|-------|-----------------------------------------------------------------------------------------------| +| Tid: | Torsdag 21. september, fra 18:00 til 20:00 | +| Sted: | Auditorium R4, Realfagsbygget | +| Pris: | Kr 50 for ikke-medlemmer, gratis for medlemmer og ITEA-ansatte (PVV-medlemsskap koster kr 42) | + +PVV arrangerer kurs i Regex, med hovedfokus pÃ¥ implementasjonen til Perl. Kurset tar for seg grunnleggende til middels avansert syntaks. Dette er et ypperlig kurs for alle som er interessert i Ã¥ gjenkjenne eller manipulere tekst, enten i Perl eller sprÃ¥k med lignende regex-syntaks (med andre ord de fleste programmeringssprÃ¥k). Kurset gir ogsÃ¥ bedre forutsetninger for Ã¥ forstÃ¥ regulære uttrykk-pensum i faget TMA4140 Diskret matematikk. + +Kurset forutsetter ingen forkunnskaper. + +Kursholder: Knut Auvor Grythe diff --git a/regex-kurs.pdf b/regex-kurs.pdf new file mode 100644 index 0000000..6bb0977 Binary files /dev/null and b/regex-kurs.pdf differ diff --git a/regex-kurs.tex b/regex-kurs.tex new file mode 100644 index 0000000..1fe821b --- /dev/null +++ b/regex-kurs.tex @@ -0,0 +1,761 @@ +\documentclass[screen]{beamer} + +\usepackage[T1]{fontenc} +\usepackage[latin1]{inputenc} + +\usepackage{beamerthemesplit} + +\parindent=0pt +\parskip=0.5\baselineskip + +\title{Regex i Perl} +\author{Knut Auvor Grythe} +\date{\today} + +\begin{document} + +\frame{\titlepage} + +%\section[Innhold]{} +%\frame{\tableofcontents} + +\section{Introduksjon} +\subsection{Litt om regex} +\frame +{ + \frametitle{Hva er Regex?} + + \begin{itemize} + \item Forkortelse for ``Regular Expression'' (``regulært uttrykk'' på norsk). + \item En kjapp og grei måte å gjenkjenne enkle tekst-strukturer på. + \item Velegnet for å gjenkjenne eller modifisere tekst på et gitt format. + \item Veldig kompakt syntaks, og dermed lite å skrive. + \item Kan brukes i de fleste programmeringsspråk (men har ofte litt varierende syntaks) + \end{itemize} +} + +\frame +{ + \frametitle{Hvordan ser en regex ut?} + + \begin{itemize} + \item En regex er i utgangspunktet bare en tekststreng, der noen få av tegnene har en spesiell betydning. + \item I en del språk (for eksempel Perl) skrives regexer med en skråstrek før og etter. + \item Denne regexen gjenkjenner teksten ``banan'': /banan/ + \end{itemize} +} + +\frame +{ + \frametitle{Hva gjør den egentlig?} + + \begin{itemize} + \item En regex går gjennom teksten \textit{fra venstre til høyre}, helt til den finner et treff. + \item En regex er grådig. Om to ulike treff begynner på samme sted i teksten, vil den alltid ta det lengste. + \item Hva som skjer når regexen matcher noe avhenger av hvordan den er brukt. + \end{itemize} +} + +\subsection{Praktisk bruk} +\frame +{ + \frametitle{Bruksområder i Perl} + + Tre vanlige bruksområder for regex i perl er matching, substitusjon og + splitting. Det finnes også andre bruksområder, men da er det i praksis + matching som utføres. + + \begin{block}{Matching} + if (\$var =\~{} /banan/) \{ + do\_stuff(); + \} + \end{block} + + \begin{block}{Substitusjon} + \$var =\~{} s/banan/eple/; + \end{block} + + \begin{block}{Splitting} + my @array = split(/a/, ``banan''); + \end{block} +} + +\frame +{ + \frametitle{Hvordan bruke andre tegn enn //} + + Selv om det er standard å skrive regexen inni //, er det fullt lovlig å + bruke andre tegn i stedet. Dette er kjekt om du skal matche et pattern med + mange /-er i, og ikke har lyst til å escape alle sammen. + + For at Perl skal kjenne igjen matching må man skrive en ``m'' foran + uttrykket, dersom man bruker noe annet enn //. + + Det er ganske vanlig å bruke komma eller kolon som tegn. + + \begin{block}{Matching} + if (\$var =\~{} m,banan,) \{ + do\_stuff(); + \} + \end{block} + + \begin{block}{Substitusjon} + \$var =\~{} s,banan,eple,; + \end{block} + +} + +\frame +{ + \frametitle{Modifikatorer} + Modifikatorer er ting du kan skrive bak uttrykket ditt for å få det til å + oppføre seg litt annerledes. Vi konsentrerer oss om de to viktigste, /g og /i. + + Modifikatorer brukes ved å plassere dem rett bak siste / i utrykket. + + \begin{block}{Eksempler} + \begin{tabular}{ll} + \textbf{/abcd/i} & et matche-uttrykk med /i.\\ + \textbf{s/abcd/blarb/g} & et substitusjons-uttrykk med /g.\\ + \textbf{s/abcd/blarb/ig} & et substitusjons-uttrykk med både /g og /i.\\ + \end{tabular} + \end{block} +} + +\frame +{ + \frametitle{Modifikatorer - Hva de gjør} + + Nå som vi vet hvordan vi slenger på en modifikator kan vi kanskje få vite + hva de gjør også :-) + + \textbf{/i} gjør at uttrykket ikke skiller på store og små bokstaver + (case-insensitive). Litt tregere enn å bare skrive inn store og små + bokstaver manuelt, siden den følger gjeldende locale, men neppe noe problem + i praksis. + + \textbf{/g} brukes kun i substitusjon, og står for ``global''. Vanligvis + vil substitusjonen bare bytte ut første treff, men med denne vil den bytte + ut \textit{alle} treff. +} + +\frame +{ + \frametitle{Kommandolinje-testing av matche-uttrykk (``grepping'')} + + \begin{block}{Perl} + echo "vi liker bananer" | perl -ne 'print if /banan/' + \end{block} + + \begin{block}{Andre språk} + echo "vi liker bananer" | grep 'banan'\newline + echo "vi liker bananer" | sed -e '/banan/p' -e 'd'\newline + echo "vi liker bananer" | awk '/banan/ \{print\}' + \end{block} + +} + +\frame +{ + \frametitle{Kommandolinje-testing av substitusjons-uttrykk (``sedding'')} + + \begin{block}{Perl} + echo "vi liker bananer" | perl -pe 's/banan/rosin/' + \end{block} + + \begin{block}{Andre språk} + echo "vi liker bananer" | sed 's/banan/rosin/'\newline + echo "vi liker bananer" | awk '\{sub(/banan/, "rosin"); print\}' + \end{block} + +} + +\section{Oversikt over syntaks} +\subsection{Spesielle tegn og hva de gjør} + +\frame +{ + \frametitle{Å matche en helt vanlig tekst-streng} + + Om du skal matche en helt vanlig tekst-streng, kan du bare skrive den rett + ut, som for eksempel /banan/ som vi har sett før. + + \begin{block}{NB!} + Husk imidlertid at enkelte tegn har spesiell betydning, og disse må escapes + om du vil ha selve tegnet. Et eksempel på dette er punktum, som kan matches + med /$\backslash$./. + + Den største forskjellen på de ulike regex-dialektene er hva som skal + escapes. En del språk tolker alt som tekst, og bruker spesialbetydningen + når du escaper i stedet. Hva andre språk gjør er imidlertid litt utenfor + skopet til kurset. + \end{block} +} + +\frame +{ + \frametitle{Liste over magiske tegn(-sekvenser)} + + \begin{tabular}{ll} + $\backslash$ & Quote the next metacharacter\\ + . & Match any character (except newline)\\ + * & Match 0 or more times\\ + + & Match 1 or more times\\ + ? & Match 1 or 0 times\\ + \{n\} & Match exactly n times\\ + \{n,\} & Match at least n times\\ + \{n,m\} & Match at least n but not more than m times\\ + \^{} & Match the beginning of the line\\ + \$ & Match the end of the line (or before newline at the end)\\ + | & Alternation\\ + () & Grouping\\ + $[ ]$ & Character class\\ + \end{tabular} +} + +\frame +{ + \frametitle{Tegnet . (punktum)} + + . (punktum) matcher et vilkårlig tegn. + + \begin{block}{Eksempel} + \textbf{/bl.pp/} matcher ``blipp'', ``blapp'', ``blupp'' og så videre. + \end{block} + + \begin{block}{NB:} + ``Vilkårlige tegn'' innebærer også whitespace, men per default ikke linjeskift (kan endres med en modifier vi snakker om senere). + \end{block} +} + +\frame +{ + \frametitle{Tegnet * (stjerne)} + + * (stjerne) sier at forrige tegn skal matches 0 eller flere ganger. + + \begin{block}{Eksempel 1} + \textbf{/bla*pp/} matcher ``blpp'', ``blapp'', ``blaapp'', ``blaaapp'' og så videre. + \end{block} + + \begin{block}{Eksempel 2} + \textbf{/bl.*pp/} matcher alt i Eksempel 1, samt f.eks. ``blupp'', ``blåbærkopp'', ``blå muggsopp'' og så videre. + \end{block} +} + +\frame +{ + \frametitle{Tegnet + (pluss)} + + + (pluss) fungerer akkurat som * (stjerne), bortsett fra at det er ``1 eller flere'' i stedet for ``0 eller flere''. + + \begin{block}{Eksempel} + \textbf{/bla+pp/} matcher ``blapp'', ``blaapp'', ``blaaapp'' og så videre, men ikke ``blpp'' (som \textbf{/bla*pp/} ville matchet). + \end{block} +} + +\frame +{ + \frametitle{Tegnet ? (spørsmålstegn)} + + ? (spørsmålstegn) sier at forrige tegn skal matches ``0 eller 1'' ganger. + + \begin{block}{Eksempel} + \textbf{/fisk?/} matcher ``fisk'' og ``fis'', og ingenting annet. + \end{block} +} + +\frame +{ + \frametitle{Tegnene \{ og \} (krøllparenteser)} + + \{ og \} brukes for å gi et egendefinert intervall over hvor mange ganger forrige tegn skal matches. + + \begin{block}{Eksempler} + \textbf{/fi\{3\}sk/} matcher ``fiiisk''.\newline + \textbf{/fi\{2,3\}sk/} matcher ``fiisk'' og ``fiiisk''.\newline + \textbf{/fi\{2,\}sk/} matcher ``fiisk'', ``fiiisk'', ``fiiiisk'' og så videre. + \end{block} + + \begin{block}{NB!} + Første argument er ikke valgfritt! \textbf{/fi\{,3\}sk/} matcher faktisk bare ``fi\{,3\}sk''. + \end{block} +} + +\frame +{ + \frametitle{Sammenhengen mellom kvantifikatorene)} + + \begin{tabular}{|l|l|}\hline + \textbf{Tegn} & \textbf{Krøllparentes-uttrykk} \\ \hline + * & \{0,\} \\ + + & \{1,\} \\ + ? & \{0,1\} \\ \hline + \end{tabular} + + Du kan med andre ord bruke kun \{ og \} om du vil, men ingen gjør det i praksis. +} + +\frame +{ + \frametitle{Tegnet \^{} og \$ (hatt og dollar)} + + \^{} og \$ matcher henholdsvis ``start of line'' og ``end of line''. + + Det vil altså si endene på variablene. Dersom det siste tegnet i variabelen + er et linjeskift, matcher den også rett før linjeskiftet. + + \begin{block}{Eksempler} + \textbf{/\^{}banan/} matcher ``banankompott'', men ikke ``stor banan''.\newline + \textbf{/banan\$/} matcher ``stor banan'', men ikke ``banankompott''.\newline + \textbf{/\^{}banan\$/} matcher kun ``banan'' eller ``banan$\backslash$n''. + \end{block} +} + +\frame +{ + \frametitle{Tegnet | (pipe)} + + | (pipe) betyr ``eller'', og er sikkert velkjent fra boolsk algebra. + Det kan settes mellom to eller flere alternativer for match. + + \begin{block}{Eksempel 1} + \textbf{/banan|eple/} matcher både ``banan'' og ``eple'' (og strenger som inneholder en eller flere av dem av dem). + \end{block} + + \begin{block}{Eksempel 2} + \textbf{/banan|eple|pære/} matcher det samme som Eksempel 1, pluss ``pære''. + \end{block} +} + +\frame +{ + \frametitle{Tegnene ``('' og ``)'' (parenteser)} + + Parenteser brukes til å gruppere, mye på samme måten som vi er vant til fra + boolsk algebra. + + De brukes også til litt annet småtteri, som vi skal se på snart. + + \begin{block}{Eksempel} + \textbf{/\^{}(banan|sviske)kompott\$/} matcher ``banankompott'' og ``sviskekompott''. + \end{block} +} + +\frame +{ + \frametitle{Tegnene [ og ] (firkantparenteser)} + + Firkantparenteser brukes når det er flere alternativer til et tegn. + Tegnene skrives rett og slett etter hverandre inni firkantparentesene. + + Firkantparenteser er egentlig et kapittel for seg, og kommer mer utfyllende senere. + + \begin{block}{Eksempel} + \textbf{/bl$[$aui$]$pp/} matcher ``blapp'', ``blupp'' eller ``blipp''. + \end{block} +} + +\subsection{Mer om gruppering} + +\frame +{ + \frametitle{Mer om parenteser} + + Som vi så for ikke så lenge siden, brukes parenteser til å gruppere ting + med. Vi så eksempelet \textbf{/\^{}(banan|sviske)kompott\$/}, der + parenteser brukes til å avgrense skopet til variable. + + Parenteser kan imidlertid også brukes til å hente ut en substreng av det + som ble matchet, og det kan vi bruke til mye rart. +} + +\frame +{ + \frametitle{Variablene \$1, \$2, \$3, etc. (1)} + + Når et uttrykk med parenteser i matcher, blir innholdet i parentesene lagt + i spesielle variable, kalt ``tilbakereferanser''. Den første påbegynte + parentesen blir lagt i \$1, den neste i \$2, og så videre. + + Merk at disse variablene må brukes med en gang, siden de forsvinner så fort + du gjør en ny regex-matching lenger nede i koden. Ta en kopi! +} + +\frame +{ + \frametitle{Variablene \$1, \$2, \$3, etc. (2)} + + Dette eksempelet plasserer ``en'' i \$a og ``to'' i \$b dersom uttrykket + matcher (og det gjør det). + + \begin{block}{Eksempel} + my \$var = "en to";\newline + my \$a;\newline + my \$b; + + if (\$var =\~{} /(.*) (.*)/) \{\newline + \hspace*{1em} \$a = \$1;\newline + \hspace*{1em} \$b = \$2;\newline + \} + \end{block} + +} + +\frame +{ + \frametitle{Direkte uthenting av tilbakereferanser} + + Om du kaller en matching i array-kontekst returneres alle + tilbakereferansene som en array. + + Ulempen med denne metoden er at du må undersøke verdiene etterpå for å få + vite om det matchet eller ikke, og det blir ikke like pent i mine øyne. + Notasjonen er heller ikke så intuitiv, spør du meg. + + Jeg ser sjelden denne konstruksjonen i bruk i praksis. + + \begin{block}{Eksempel} + my \$var = "en to";\newline + my (\$a, \$b) = \$var =\~{} /(.*) (.*)/; + \end{block} +} + +\frame +{ + \frametitle{Bruk av tilbakereferanser i substitusjons-uttrykk} + + Du kan også bruke \$1 med venner i substitusjoner. + + \begin{block}{Eksempel} + \# Dette bytter om på ``en'' og ``to''.\newline + my \$var = ''en to'';\newline + \$var =\~{} s/(.*) (.*)/\$2 \$1/; + \end{block} + + \begin{block}{PS:} + En del andre språk, som f.eks. sed og vim, bruker $\backslash$1 i stedet + for \$1 og så videre. + \end{block} +} + +\frame +{ + \frametitle{Bruk av tilbakereferanser inne i selve patternet} + + Om du vil, kan du også bruke tilbakereferanser til en tidligere del av + patternet lenger ute i regexen. Dette kan for eksempel være kjekt om du + skal matche en serie av like tegn, men det er mer enn ett alternativ for + hvilket tegn det er. + + Når du gjør tilbakereferanser inne i selve patternet, må du bruke + $\backslash$1 i stedet for \$1 og så videre. \$1 og lignende vil + \textit{ikke} virke! De er nemlig ikke definert ennå. + + \begin{block}{Eksempel: Fjerning av trippelkonsonanter} + my \$var = ''busssjåfør'';\newline + \$var =\~{} s/(.)$\backslash$1+/\$1\$1/g; + \end{block} +} + +\frame +{ + \frametitle{Viktig bruksområde: Tainting} + + Tainted mode er en feature i Perl som tvinger deg til å sjekke inputen din + til scripts. Det er et nyttig verktøy for å unngå lite kledelige + sikkerhetshull i webapplikasjoner, for eksempel. + + Tainted mode virker slik at det eneste du får lov å bruke innleste (ergo + potensielt skumle) variabler til, er å kjøre regex-matching på dem. Så kan + du hente ut \$1 med venner derfra, og bruke dem. + + Tainted mode slås på med opsjonen -T bak perl-programmet. +} + +\frame +{ + \frametitle{Hvordan gruppere uten at innholdet huskes} + + Om du ønsker å bruke parenteser til gruppering, men \textit{ikke} ønsker å + bruke innholdet i parentesen etterpå, kan du bruke ``?:'' først i + parentesen. + + Dette er spesielt nyttig i split(), men også greit om du har masse + parenteser du vil huske, men så plutselig noen du ikke vil huske midt inni. + Det sparer også bittelitt minne, men det er mindre viktig. + + \begin{block}{Eksempel} + \# returnerer (``b'', ``a'', ``n'', ``a'', ``n'', ``e'', ``r'')\newline + my @a = split(/(a|e)/, "bananer"); + + \# returnerer (``b'', ``n'', ``n'', ``r'')\newline + my @b = split(/(?:a|e)/, "bananer"); + \end{block} +} + +\subsection{Mer om tegnklasser} + +\frame +{ + \frametitle{Et gjensyn med $[$ og $]$} + + For en stund siden snakket vi så vidt om $[$ og $]$, som brukes for å + definere en klasse av tegn. De skal vi snakke litt mer om nå. + + La oss først huske at en serie med tegn i firkantparenteser betyr at vi + matcher ett av tegnene i firkantparentesen en gang. + + \begin{block}{Eksempel} + \textbf{/$[$abc$]$/} matcher ett tegn, som kan være enten ``a'', ``b'' + eller ``c''. + \end{block} +} + +\frame +{ + \frametitle{Matching av fleksibelt antall tegn med tegnklasse} + + Skal vi matche et annet antall tegn enn nøyaktig ett, må vi (som vanlig) + bruke en kvantifikator som f.eks. *, +, ? eller \{m,n\}. + + \begin{block}{Eksempel} + \textbf{/$[$abc$]$+/} matcher ett eller flere tegn, som kan være enten + ``a'', ``b'' eller ``c''. + \end{block} +} + +\frame +{ + \frametitle{Tegnsekvenser} + + Siden det er litt tiltak å skrive tegnklasser som for eksempel + \textbf{$[$0123456789$]$}, \textbf{$[$abcdef$]$} og sånt, har man mulighet + for å angi intervaller. Dette gjøres med bindestrek. + + \begin{tabular}{|l|l|}\hline + \textbf{Sekvens} & \textbf{Tilsvarer} \\ \hline + \textbf{$[$0-9$]$} & \textbf{$[$0123456789$]$} \\ + \textbf{$[$a-f$]$} & \textbf{$[$abcdef$]$} \\ + \textbf{$[$0-9a-f$]$} & \textbf{$[$0123456789abcdef$]$} \\ + \hline + \end{tabular} + + \begin{block}{Eksempel} + \textbf{/\^{}0x$[$0-9a-fA-F$]$+\$/} matcher et hexadecimalt tall, som for + eksempel ``0x1337babe''. + \end{block} +} + +\frame +{ + \frametitle{Negasjon} + + Av og til ønsker du å matche alt unntatt visse tegn, som for eksempel alt + unntatt kolon. For å gjøre dette kan du bruke en negert tegnklasse. Dette + gjøres ved å sette tegnet \^{} (hatt) fremst i tegnklassen. + + Det stemmer, hatt betyr noe helt annet inni en tegnklasse enn den betyr + utenfor. Litt forvirrende i starten, men det går fort over. + + \begin{block}{Eksempel} + \textbf{/\^{}($[$\^{}:$]$*)/} matcher fra starten av strengen til første + kolon (eller slutten av strengen, om det ikke finnes noe kolon i den) og + legger resultatet i \$1. + \end{block} +} + +\frame +{ + \frametitle{Escaping av spesielle tegn i tegnklasser} + + Siden \^{} (hatt), - (bindestrek) og $]$ har spesiell betydning i en + tegnklasse ($]$ avslutter klassen), må man escape dem om man vil ha et + bokstavelig tegn. + + Dette kan gjøres enten ved å escape dem med backslash, eller ved å plassere + dem spesielle steder i tegnklassen. I praksis brukes ofte spesiell + plassering, siden dette er vanlig i andre regex-implementasjoner. + + \begin{tabular}{|l|l|} \hline + \textbf{Tegn} & \textbf{Plassering for å escape} \\ \hline + \^{} (hatt) & Et annet sted enn fremst \\ + - (bindestrek) & Helt bakerst eller helt fremst (bak eventuell hatt) \\ + $]$ & Helt fremst (bak eventuell hatt) \\ + \hline + \end{tabular} +} + +\frame +{ + \frametitle{Ferdigdefinerte tegnklasser} + + Perl har også en del ferdigdefinerte tegnklasser. Disse kan brukes enten som byggestener i egendefinerte tegnklasser, eller for seg selv. + + Eksemplene nedenfor benytter $\backslash$w, som matcher tegn som kan være i + ord (det vil si bokstaver, tall og \_ (underscore)). + + \begin{block}{Eksempler} + \textbf{/($\backslash$w+)/} henter ut det første ordet og legger det i \$1. + + \textbf{/($[$$\backslash$w-$]$+)/} gjør som forrige eksempel, men tillater + bindestrek i ordet. + \end{block} +} + +\frame +{ + \frametitle{Liste over ferdigdefinerte tegnklasser} + + Dette er en liten oversikt over de mest brukte ferdigdefinerte + tegnklassene. Det finnes en del flere, men de er ikke like vanlige. Du + finner dem i ``perldoc perlre''. + + \begin{tabular}{|l|l|}\hline + \textbf{Klasse} & \textbf{betydning} \\ \hline + $\backslash$w & Match a "word" character (alphanumeric plus ``\_'')\\ + $\backslash$W & Match a non-"word" character\\ + $\backslash$s & Match a whitespace character\\ + $\backslash$S & Match a non-whitespace character\\ + $\backslash$d & Match a digit character\\ + $\backslash$D & Match a non-digit character\\ + $\backslash$b & Match a word boundary\\ + \hline + \end{tabular} +} + +\section{Eksempler og avslutning} + +\subsection{Eksempler} + +\frame +{ + \frametitle{Eksempel: Strippe HTML} + + Dette eksempelet har dere sikkert sett før, på plakaten til kurset. Nå har + dere sikkert lært nok til å se hva den gjør også! + + Merk at om du leser inn en linje om gangen vil ikke denne koden støtte + html-tags som går over flere linjer. + + Vi ser at uttrykket matcher en <, så innholdet i tagen (ett eller flere + tegn som ikke er >, og så til slutt >. Substitusjonen er også global, så + alle treffene blir erstattet med en tom streng. + + \begin{block}{Eksempel} + \textbf{s/<$[$\^{}>$]$+>//g} + \end{block} +} + +\frame +{ + \frametitle{Eksempel: Hente ut linker fra HTML} + + Om du vil hente ut alle linkene i et HTML-dokument, kan du for eksempel + matche på det som er i hermetegn bak ``href=''. + + \textbf{$\backslash$s*} er med her og der fordi det er valgfritt med mellomrom der. + + \begin{block}{Eksempel} + \textbf{/href$\backslash$s*=$\backslash$s*''([\^{}'']+)/i} + \end{block} + + \begin{block}{I praktisk bruk} + \textbf{perl -ne 'print ''\$1$\backslash$n'' if /href$\backslash$s*=$\backslash$s*''([\^{}'']+)/i' fil.html} + \end{block} +} + +\frame +{ + \frametitle{Eksempel: Hente ut flere linker per linje fra HTML} + + Eksempelet på forrige slide hadde en begrensning: Det støttet bare en link + per linje. Det er sikkert fullt mulig å lage en regex som støtter å fiske + ut flere, og legge dem i \$1, \$2 og så videre, men det blir bare tungvint + og ekkelt. I stedet kan vi enten modifisere input-dataene (f.eks. legge inn + linjeskift mellom alle HTML-tags) eller kjøre flere matchinger per linje. + Vi satser på å gjøre flere matchinger per linje. + + Her har vi samme regex som i stad, men substituerer bort patternet i stedet + for å matche det. Slik holder vi på til det ikke er mer som matcher. + + \begin{block}{Eksempel} + \textbf{perl -ne 'print ''\$1$\backslash$n'' while s/href$\backslash$s*=$\backslash$s*''([\^{}'']+)//i' fil.htm} + \end{block} +} + +\frame +{ + \frametitle{Eksempel: Matche primtall} + + Følgende kode matcher et primtall. Den er vel kanskje ikke kjempe-intuitiv, + men virker for små primtall. For store primtall går den kjapt tom for minne + og tryner. + + Dette er for øvrig omtrent tregest tenkelige måte å regne ut om noe er + primtall eller ikke, så den bør kun brukes som kuriositet ;-) + + Den fungerer ved at man først matcher to eller flere tegn, før man matcher + denne sekvensen to eller flere ganger. I praksis bruteforcer man altså om + tallet er delelig med noe. + + \begin{block}{Eksempel} + perl -e '(1x\$ARGV$[$0$]$) =\~{} /\^{}(..+?)$\backslash$1+\$/ || print ``prime$\backslash$n''' + \end{block} +} + +\subsection{Avslutning} + +\frame +{ + \frametitle{Generelle triks} + + Når du skriver en regex er det noen få triks som gjerne sparer deg for en + del hodebry: + + \begin{itemize} + \item Gjør den enkel først, legg på særtilfeller etter hvert. + \item Test at den gjør det du vil underveis. Det er fort gjort å snike inn + en skrivefeil som ødelegger alt. + \item Om regexen blir kjempediger og fæl, stopp og tenk på hvorvidt dette + egentlig var rett verktøy å bruke. Kanskje du bør lage en skikkelig + parser i stedet? + \item Av og til kan det være kjekt å først matche på et grovt pattern, + hente ut det som er interessant, og så matche videre med en ny regex. + \end{itemize} +} + +\frame +{ + \frametitle{Hva er Regex IKKE bra til?} + + Nå som vi har sett at regex gjør det mulig å gjøre masse flott, er det kanskje en plan å se litt på hva det \textit{ikke} passer så bra til. + + \begin{itemize} + \item Regex støtter ikke rekursjon. Dette gjør det håpløst å matche f.eks. + HTML skikkelig, siden vi ikke kan holde styr på start- og slutt-tager. + \item Om teksten er litt komplisert er det ofte vel så greit å skrive en + skikkelig parser, i stedet for en supergrisete regex. + \item Regex er ikke veldig maintainable, spesielt ikke om du overdriver. + \end{itemize} +} + +\frame +{ + \frametitle{Hvordan lære mer?} + + Om du vil lære mer, er det selvsagt et triks å bruke regex en del. Selv + bruker jeg bortimot daglig regex til et eller annet, som regel i + forbindelse med små onelinere jeg bruker for å massere tekst. Jeg bruker + det også mye for å gjøre søk og erstatt i vim (jeg har brukt en del regexer + i vim mens jeg skrev disse foilene). + + Om du vil lese mer, er kommandoen ``perldoc perlre'' veldig fin. O'Reilly + har også noen bøker jeg tror er bra, og et par av dem ligger sikkert på + PVV. + + Har man et obskurt problem er det også ofte hjelp å få på IRC, eventuelt på + mailinglister med nerder på (som f.eks. aktive@pvv.ntnu.no). +} + +\end{document}