Recover from microbel

This commit is contained in:
Kursmester 2025-03-05 11:17:00 +01:00 committed by h7x4
commit 75e7d0675f
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
3 changed files with 795 additions and 0 deletions

34
README.md Normal file

@ -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

BIN
regex-kurs.pdf Normal file

Binary file not shown.

761
regex-kurs.tex Normal file

@ -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}