1 \documentclass[titlepage, twoside,
a4paper,
12pt
]{article
}
2 \usepackage[swedish
]{babel
}
3 \usepackage[utf8
]{inputenc}
8 % Include pdf with multiple pages ex \includepdf[pages=-, nup=2x2]{filename.pdf}
9 \usepackage[final
]{pdfpages
}
10 % Place figures where they should be
15 \def\preTitle{Laboration
3: Information Retrieval \& Extraction
}
16 \def\kurs{Artificiell Intelligens med inriktning mot kognition och
19 \def\namn{Anton Johansson
}
20 \def\mail{dit06ajn@cs.umu.se
}
21 \def\namnett{Victor Zamanian
}
22 \def\mailett{dit06vzy@cs.umu.se
}
24 \def\handledareEtt{Dennis Olsson, denniso@cs.umu.se
}
25 \def\inst{datavetenskap
}
26 \def\dokumentTyp{Laborationsrapport
}
32 \begin{tabular
}{@
{}p
{\textwidth}@
{}}
33 UMEÅ UNIVERSITET
\hfill \today \\
34 Institutionen för
\inst \\
41 \huge{\textbf{\kurs}} \\
50 \large{\textbf{Handledare
}}\\
51 \mbox{\large{\handledareEtt}}
59 \rhead{\footnotesize{\today}}
60 \lhead{\footnotesize{\namn,
\mail \\
\namnett,
\mailett}}
65 \fancyfoot[LE,RO
]{\thepage}
69 Reguljära uttryck (Regular Expressions) är uttryck som innehåller
70 olika syntax för att identifiera, eller ''matcha'', specifika
71 textsträngar ur en större mängd text. Det finns många olika
72 användningsområden för reguljära uttryck inom området Artificiell
73 Intelligens, till exempel att hämta data från dokument på Internet och
74 tolka det utifrån någon preferens; ''Sök (och ersätt)''-funktioner i
75 ordbehandlare och textredigerare; och tolkning och validering av data,
76 till exempel datum-, telefon-, och personnummerinmatning i
90 \pagenumbering{arabic
}
92 % TODO @anton - Problem-solving as search, basic to AI, Norvig.
94 \section{Introduktion
}
96 Denna rapport går igenom användandet av Reguljära uttryck (Regular
97 Expressions på engelska, även förkortat som ''regexp'' eller bara
98 ''regex'') med avseende på informationshämtning inom området
99 Artificiell Intelligens.
101 Rapporten är formulerad och utförd enligt specifikation på sidan:\\
103 \verb!http://www.cs.umu.se/kurser/
5DV063/HT08/assignments/lab3-spes-ht08.html!
107 % med uppgiften, beskrivet med egna ord.
108 %% Syftet med rapporten är att fördjupa sig inom ett smalt ämne inom
109 %% området Artificiell Intelligens och presentera teori för det valda
110 %% ämnet på ett vetenskapligt sätt.
112 Syftet med rapporten är att undersöka hur reguljära uttryck fungerar,
113 och hur kan de kan användas inom ämnet Artificiell Intelligens.
115 \section{Metodbeskrivning
}
116 %: beskrivning av metod, material, design och procedur
117 Denna rapport är sammanställd främst genom en litteratur\-studie inom
118 om\-rådet Artificiell Intelligens i förhållande till Reguljära uttryck.
119 Information och tankar är samlade från böcker och internetsidor, för
120 att försöka få en överblick över de Reguljära uttryckens betydelse och
121 användande inom om\-rådet.
124 %, teoretisk fördjupning, f d Litteraturstudie
125 Enligt Jurafski
\emph{et al.
} \cite{speech
} härstammar Reguljära
126 uttryck från Alan Turings modell (
1936) för aritmetisk beräkning, även
127 kallad Turingmaskin. Denna maskin var abstrakt, ett tankeexperiment,
128 för att utföra beräkningar.
129 % TODO Church-Turings hypotes säger att varje tänkbar process kan
130 % utföras av en Turingmaskin, och alltså finns det rent principiellt
131 % inte någon mer kraftfull beräkningsmekanism. Enligt wikipedia
132 % http://sv.wikipedia.org/wiki/Turingmaskin
133 Inspirerad av Turings arbete skapade sedan Warren McCulloch och Walter
134 Pitts (
1943) en förenklad modell för neuronen, se
\cite{norvig
}
135 kapitel
18. Stephen Cole Kleene definierade sedan (
1951 och
1956) ändlig
136 automation (Finite Automation) och reguljära uttryck och påvisade deras
137 likhet. Både reguljära uttryck och Finite Automation är en del av den språktyp
138 som brukar kallas
\emph{reguljära språk
}, (Regular Language).
140 I boken ''Speech and language processing
\ldots ''
\cite{speech
} av Jurafski
141 \emph{et al.
} ges ett exempel på hur Finite automation och Reguljära
142 uttryck förhåller sig till varandra. Säg att ett naturligt språk ska
143 definieras. För enkelhets skull försöker definieras ''ko-språk''. I
144 detta exempel är ett korrekt ''ko-språk'' definierat av
154 Detta skulle kunna beskrivas med en modell för
\emph{Finite-state
155 automation
} (ändlig automat) enligt Figur~
\ref{fig:finauto
}.
159 \includegraphics[width=
110mm
]{images/state.pdf
}
160 \caption{Ändlig automat för ''ko-språk''
}
165 Tillstånden
\verb!q0-q4! är de giltiga tillstånd som finns,
\verb!q1!
166 är start\-tillståndet och
\verb!q4! representerar sluttillstånd. Pilarna
167 i figuren markerar möjliga för\-flyttningar mellan till\-stånden.
169 Denna information går även att representera som en
170 \emph{State-transition-tabell
}, som i
171 Tabell~
\ref{tab:statetranstable
}.
175 \begin{tabular
}{|c|l|l|l|
}
177 &
\multicolumn{3}{|c|
}{Indata
} \\
179 Tillstånd & M & u & ! \\
188 \caption{State-transition-tabell för ''ko-språk''.
}
189 \label{tab:statetranstable
}
192 State-transistion-tabeller läses uppifrån och ner. Starttillståndet
0
193 har en giltig förflyttning till tillstånd
1, detta gäller
194 enbart för indata M, för alla andra indata finns inga giltiga
195 förflyttningar, detta markeras med
0.
197 Det korresponderande
\textbf{Reguljära uttrycket
} för att beskriva
198 ''ko-språk'' skulle vara:
204 Detta läses ungefär som vanlig text.
\verb!M! är tillåtet
205 starttillstånd, följt av ett
\verb!u!, sedan markerar operatorn
206 \verb!u+! att en eller flera
\verb!u! är tillåtna. Meningen avslutas
207 med
\verb?!?, vilket leder till sluttillståndet i exemplet.
208 % Se sektion TODO för mer info om regexp syntax.
211 \section{Litteraturstudie
}\label{litteraturstudie
}
213 % Står på sidan 848 i Norvig.
215 Följande avsnitt baseras på definitionen av reguljära uttryck som ges
216 i böckerna
\cite{norvig, friedl
} och Internet-sidan
217 \cite{regexinfo:website
}.
219 Ett reguljärt uttryck består enkelt nog av text som ska matchas. Om
220 texten ''hej'' ska matchas i en textsträng ''hoppsanhejsan'' så blir
221 det reguljära uttrycket helt enkelt bara ''hej'' och ''hej'':et i
222 ''hoppsanhejsan'' matchas. Däremot är det mer sällan man använder
223 reguljära uttryck för sådana enkla matchningar. Man vill i stället
224 använda dem till att matcha
\textbf{generella mönster
}. Ett exempel på
225 ett mönster skulle kunna vara en e-postadress på formen
226 \verb!<användarnamn>@<subdomän>.<domän>!, där
\verb!<användarnamn>!
227 kan innehålla (i detta exempel) alla siffror, alla små och stora
228 bokstäver (från A till Z), understreck, punkt, procenttecken,
229 bindestreck och plus.
231 I stället för att behöva skriva ett textmönster för varje e-postadress
232 som är möjlig att konstruera (i praktiken oräkneligt antal
233 variationer) kan man använda sig av speciella ''texthändelser'' för
234 att beskriva till exempel början
\slash slutet av ett ord och
235 början
\slash slutet av en hel sträng. Man kan också definiera
236 teckenklasser som man vill inkludera i sitt uttryck, till exempel alla
237 stora bokstäver, alla små bokstäver, siffror, eller till och med
238 vilken godtycklig kombination av tecken som helst. I
239 Tabell~
\ref{tab:texthandelser
} (sammanställt från
\cite{friedl
}),
240 visas en kort tabell med några texthändelser och deras motsvarande
246 \begin{tabular
}{|c|p
{4cm
}|l|l|l|
}
248 \textbf{regex-uttryck
} &
\textbf{Texthändelse
} &
\textbf{Exempel
} &
\textbf{Matchar
} \\
\hline
250 \verb!
\b! & Början eller slutet på ett ord &
\verb!
\b!text
\verb!
\b! & ''ord1
\textbf{text
} ord3'' \\
\hline
252 \verb!^! & Början av en textsträng &
\verb!^!text & ''
\textbf{text
} i början'' \\
\hline
254 \verb!$! & Slutet av en textsträng &
\verb!lutet$! & ''text i s
\textbf{lutet
}'' \\
\hline
256 \verb!
[A-Za-z0-
9]! & Definierar klass med tecknen A till Z, a
257 till z och
0 till
9. &
\verb!
[abc0-
9]! & ''
\textbf{b
}r
\textbf{a
} text med
\textbf{23} te
\textbf{c
}ken'' \\
261 \verb!.! (punkt) & Står för vilket tecken som helst. &
\verb!^.! & ''
\textbf{t
}ext'' \\
\hline
264 \caption{Texthändelser och deras motsvarande reguljära uttryck.
}
265 \label{tab:texthandelser
}
268 Om man vill matcha en e-postadress i löpande text skulle man alltså
269 vilja använda sig av
\verb!
\b! runt uttrycket för att markera att det
270 som finns runt omkring adressen måste vara ordavgränsare av något
271 slag, dvs. någon typ av blanktecken. Vill man däremot kontrollera
272 indata från till exempel ett formulärfält där det är meningen att en
273 användare ska ange enbart en e-postadress är det däremot önskvärt att
274 omsluta uttrycket med
\verb!^! i början och
\verb!$! i slutet för att
275 markera att hela strängen måste
\textbf{börja och sluta med
} adressen.
277 Låt oss definiera en teckenklass med alla siffror, dvs
278 ''
\verb!
[0-
9]!'' och använda det i ett reguljärt uttryck, till exempel
279 ''
\verb!
\b\$
[0-
9]!''. Om vi sedan försöker matcha strängen ''\$
10000''
280 med det mönstret kommer vi endast matcha följande (fet stil)
281 ''
\textbf{\$
1}0000''. Detta beror på att teckenklassen vi definierat
282 matchar bara
\textit{det första
} tecknet som platsar i
283 klassen. Självklart skulle vi vilja kunna matcha flera tecken i en och
284 samma teckenklass utan att behöva definiera en likadan klass för hela
285 det antalet tecken vi vill matcha. Därför har man definierat något som
286 kallas kvantifierare som gör att man kan bestämma hur många gånger man
287 vill matcha en specifik klass, ett mönster eller bara ett tecken (så
288 kallade ''tokens''). Tabell
\ref{tab:kvantifs
} (innehåll sammanställt
289 från
\cite{friedl
}), beskriver olika kvantifierare.
294 \begin{tabular
}{|c|p
{4cm
}|l|p
{4cm
}|
}
296 \textbf{kvantifierare
} &
\textbf{Beskrivning
} &
\textbf{Exempel
} &
\textbf{Matchar
} \\
\hline
298 \verb!?! & Matchar föregående uttryck noll eller en gång. &
299 colou
\verb!?!r & ''
\textbf{colour
}'' och ''
\textbf{color}'' \\
\hline
301 \verb!+! & Matchar föregående uttryck en eller fler gånger. &
302 Mu
\verb:+:! & ''
\textbf{Mu!
}'', ''
\textbf{Muu!
}'',
303 ''
\textbf{Muuu!
}'',
\ldots \\
\hline
305 \verb!*! & Matchar föregående uttryck noll eller flera gånger &
306 10\verb!*! & ''
\textbf{1}'', ''
\textbf{10}'', ''
\textbf{100}'',
309 \verb!
{!$n$
\verb!,!$m$
\verb!
}! & Matchar föregående uttryck
310 minst $n$ gånger och som mest $m$ gånger. &
311 \verb!^!
1\verb!
[!
0\verb!
]{!
1,
5\verb!
}! & ''
\textbf{10}'',
312 ''
\textbf{100}'', ''
\textbf{1000}'', ''
\textbf{10000}'' och
313 ''
\textbf{100000}'' men inte ''
1'' och inte ''
1000000'' (
6
314 nollor eller mer).\\
\hline
317 \caption{Reguljära kvantifierare, deras funktion och exempel på vad som matchas.
}
321 Nu kan vi beskriva många olika variationer av mönster genom olika
322 text\-händelser och kvantifierare, men vad händer om man vill inkludera
323 till exempel ett frågetecken i sitt mönster? Då måste man ''komma
324 runt'' (escape) frågetecknets regexp-betydelse för att komma åt dess
325 textuella värde. Detta görs vanligtvis med bakåtvänt snedstreck
326 (
\textbackslash). Till exempel måste vi i vårt e-post\-adress\-mönster
327 matcha en punkt (i domännamnet), som vi måste uttrycka som
330 Nu har vi tillräckligt stor kunskap för att uttrycka ett reguljärt
331 uttryck som matchar en generell e-post\-adress. Vi börjar med att
332 beskriva segmentet
\linebreak\verb!<användarnamn>!. Användar\-namnet
333 kunde som sagt var innehålla små och stora bokstäver (från A till Z),
334 siffror, punkt, under\-streck, procent\-tecken, plus\-tecken och
335 binde\-streck. Vi uttrycker detta som
341 där det sista plustecknet som sagt innebär att alla de tecken som den
342 definierade tecken\-klassen innefattar måste matchas minst en
343 gång. Plustecknet inom tecken\-klass\-definitionen tolkas som ett
344 ''textplus'' och inte som ett ''regex-plus''. Vi lägger också till
345 ordavgränsare som gör att uttrycket bara matchar användarnamnet i
346 början av ett nytt ord (dvs. själva e-post\-adressen) och inte matchar
347 ett användarnamn när det kommer direkt efter ett icke tillåtet
348 användarnamnstecken. Hade vi glömt ordavgränsaren hade följade
349 användarnamn matchats:
350 \\ ''
\copyright\&
\texttrademark\textexclamdown\textbf{sven.svensson
}@host.doman''
351 vilket vi inte vill eftersom de icke tillåtna tecknen inte bör finnas
354 Vi uttrycker sedan domännamnet som
357 [A-Za-z0-
9.-
]+\.
[A-Za-z
]{2,
4}\b
360 där plustecknet betyder precis samma sak som i uttrycket för
361 användar\-namnet och ''
\verb!\.!'' står för punktens textuella
362 värde. Sedan finns det ett krav på det som står efter punkten i
363 domännamnet, nämligen att denna ''token'' måste bestå av minst
2 och
364 som mest
4 tecken, därav kvantifieraren
\verb!
{!
2\verb!,!
4\verb!
}!.
365 \verb!
\b! i slutet av uttrycket innebär att det måste finnas en
366 ordavgränsare efter domännamnet.
368 Sätter vi nu samman dessa uttryck med ett snabel-a i mitten får vi ett
369 uttryck för en generell e-post\-adress
\textbf{i löptext
}. Vill vi
370 definiera ett uttryck för att undersöka om totala textmängden består
371 av endast en e-post\-adress kan vi ersätta
\verb!
\b! i början med
372 \verb!^! och i slutet med
\verb!$! (till exempel om vi vill
373 kontrollera ett formulärfält på en webbsida)
374 \cite{regexinfo:website
}. De två olika uttrycken ser ut som följer:
377 \b[A-Za-z0-
9._
%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\b
383 ^
[A-Za-z0-
9._
%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$
386 % Olika sätt att matcha e-mail adresser.
387 % \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\b
388 % ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$
389 % http://www.regular-expressions.info/email.html
392 % innehållande sammanställning/analys av eventuell testdata,
393 % implementering av algoritmer osv.
395 % TODO - resultat, användningsområden kopplade till AI.
397 Följande avsnitt tar upp några exempel på existerande applikationer av
398 reguljära uttryck inom ämnet Artificiell intelligens och ett
399 konstruerat exempel, avsnitt
\ref{datah
}. Resultatet baseras på
400 funktionerna som beskrivs i avsnitt~
\ref{litteraturstudie
}.
402 \subsubsection{ELIZA
}
403 Mer avancerade former av Reguljära uttryck kan använda sig av
404 minnesfunktioner för att spara tidigare matchningar. I
405 programmeringssråket Perl kan man göra ersättningar på formen:
410 Här ersätts alla
\verb!hej! med
\verb!hejsan!. För att spara träffar i
411 sökningen och ersätta med samma ord i ersättningssträngen använder man
412 grupper inom parenteser
\verb!()!. Den sträng som en grupp matchar kan
413 sedan refereras till.
\verb!
\1!, till exempel, representerar
414 innehållet i första gruppen.
417 s/jag heter (
\w+)/på dig
\1, trevligt att höras/
420 Ovanstående Reguljärt uttryck skulle ersätta ''Hej jag heter Anton''
421 med ''Hej på dig Anton, trevligt att höras''. Denna typ av Reguljära
422 ersättningar utgör grunden för implementationen av Chatroboten ELIZA,
423 som utvecklades av Joseph Weizenbaum, se
\cite{speech
}. Här följer en
424 kort konversation med Emacs implementering av ELIZA:
427 \item[-
] Hello my name is Anton
428 \item[-
] \textbf{ELIZA:
} How do you do? What brings you to see me?
429 \item[-
] I need help with some Artificial Intelligence questions
430 \item[-
] \textbf{ELIZA:
} Why do you say you need help with some
431 artificial intelligence questions?
432 \item[-
] I'm writing an essay about Regular Expressions
433 \item[-
] \textbf{ELIZA:
} Is it because of your plans that you say you
434 are writing an essay about regular expressions?
436 \item[-
] \textbf{ELIZA:
} I see... Well, what makes you believe this is so?
439 Ovanstående exempel vittar om att denna typ av chatrobot har en
440 relativt fast ram med frågor och svar att följa. Det tar inte lång tid
441 för en mänsklig användare att förstå att det inte är en mänsklig
442 motpart man kommunicerar med. ELIZA är implementerad för att svara på
443 frågor som rör psykoterapi--så fort man lämnar det bekanta ämnet blir
444 följdfrågorna ologiska ur ett mänskligt perspektiv.
446 Emacs implementation av ELIZA har en mängd hårdkodade svar, se källkod
447 \cite{doctor:website
}. Följande kodsnutt visar svaren som kan fås av indata som
448 innehåller vissa nyckelord gällade död:
453 '((this is not a healthy way of thinking \.)
454 ((doc$ bother) you\, too\, may die someday \?)
455 (i am worried by your obsession with this topic!)
456 (did you watch a lot of crime and violence on television as a child \?))
461 Även mängder med vanliga ord sparas för att på ett bättre sätt kunna
462 tolka indata, exempelvis vanliga synonymer, pronomen, verb och förkortningar:
476 \subsubsection{Tolkning av indata
}
477 Det finns en mängd användbara Reguljära uttryck för att tolka och på
478 ett vettigt sätt behandla indata som ett datorsystem får från
479 användare. Det kan gälla exempelvis verifiering av e-postadresser,
480 datum, person- och telefonnummer och så vidare. Detta är användbart
481 vid all typ av indata från användare, och i hög grad aktuellt när det
482 gäller forumlär på Internet.
484 Till exempel kan man istället för att kräva att användare ska skriva
485 för- och efternamn i separata rutor använda Reguljära uttryck för att
486 försöka tolka vad som är vad. Samma sak gäller adresser och
487 telefonnummer. Det kan vara intressant att ha information och ett
488 telefonnummers riktnummer och landskod, utan att för den sakens skull
489 kräva att en användare ska behöva specificera allt sådant manuellt.
490 Följer man bara vanliga konventioner för hur telefonnummer skrivs kan
491 man skapa ett Reguljärt uttryck för att fånga upp all denna
492 information ur en enda textsträng. All sådan här tolkning av indata är
493 väldigt bra ur användarsynpunkt, ''Don't make me click'', som Aza
494 Raskin säger i en presentation om användarvänlighet på webbsidor
495 \cite{raskin:website
}.
497 %@TODO fixa url löpande
498 Ett annat bra exempel på hur Reguljära uttryck kan underlätta
499 inmatning av data finns implementerat i den webbaserade
500 kalendertjänsten från Google Inc.
501 (
\begin{footnotesize
}http://google.com/calendar/
\end{footnotesize
}).
502 För att skapa en ny händelse i kalendern kan användaren klicka på
503 aktuell dag och skriva till exempel ''Äta mat hos mamma kl
504 10-
12''. Detta genererar en händelse med rubrik ''Äta mat hos mamma''
505 och placeras med start kl
10 och slut kl
12 i kalendern. Ett Reguljärt
506 uttryck för detta skulle kunna vara att matcha de första siffrorna
507 efter
\verb!(kl|klockan)!, dessa borde vara starttimme för
508 händelsen. Följs dessa siffror av
\verb!.! eller
\verb!:! utan
509 mellanslag efter skulle nästa två siffror kunna representera minuter,
510 nästa siffror, eventuellt efter ett bindestreck, kan representera
511 sluttid. På detta sätt kan man med hjälp av Reguljära uttryck
512 representera naturligt språk för datorn. Vidare skulle extra nyckelord
513 kunna läggas in, till exempel
\verb!hos!,
\verb!på! eller
\verb!i! för
514 att markera att det som följer är en plats, eller
\verb!med! för att
515 markera att följande text innehåller information om deltagare i
518 \subsubsection{Datahämtning
} \label{datah
}
519 Reguljära uttryck kan användas för att hämta och tolka information ur
520 en större mängd data. Ett trivialt exempel är till exempel att försöka
521 svara på frågan, ''Vad är det för väder i Umeå idag?'' baserat på
522 innehållet från sidan:
525 http://www.tfe.umu.se/weather/
1440/
900/
10/sv-SE/now.htm
528 Html-taggen som visar den aktuella temperaturen i Umeå har följande
531 <td class="tempfont" ... >
0,
7 °C</td>
534 Det som skiljer denna tagg från de andra på sidan är attributet
\linebreak
535 \verb!class="tempfont"!. Den aktuella temperaturen visas mellan
536 \verb!<td ...>! och
\verb!</td>!, det innebär att det i detta exempel
537 skulle vara $
0,
7\,^
{\circ}\mathrm{C
}$ dagen sidan hämtades. Följande
538 Reguljära uttryck matchar den strängen som innehåller temperatur i sin
539 första grupp, dvs uttrycket inom
\verb!()!, som senare kan refereras
543 <td class="tempfont.+?>(
[0-
9]+,
[0-
9]+)
546 Med denna information kan man sedan förenkla och säga att bra väder
547 gäller för alla $temperaturer
\geq 15$ och dåligt väder gäller för
548 $temperaturer <
15$. Detta Reguljära uttryck är mycket specifikt och
549 enbart användbart på denna specifika sida så länge temperaturen
550 inkapslas exakt av den HTML-taggen och eventuella attribut.
553 % av resultatet, koppling till tidigare studier.
554 Reguljära uttryck har visat sig vara ett mycket användbart verktyg vid
555 hämtning och tolkning av data ur text, dock kan det bli väldigt
556 beräknings\-tungt om man använder sig av de mer komplicerade former av
557 Reguljära uttryck där man sparar undan grupper av träffar i
558 minnet. Den simplaste formen av Reguljära uttryck har en komplexitet
559 på $O(n)$ där $n$ är antalet tecken i texten där ett mönster söks.
560 Dessa typer av Reguljära uttryck kan implementeras med en
561 ''State-transition-tabell'', se sid
\pageref{tab:statetranstable
}. Vid
562 användande av mer avancerade Reguljära uttryck kan körningstiden öka
563 exponentiellt i förhållande till textmängden som ska sökas igenom.
565 För analys av data i XML-format som i sektionen om Datahämtning
566 \textbf{\ref{datah
}} finns lämpade metoder såsom XQuery, Expat och
570 Reguljära uttryck har visat sig vara mycket användbara inom vitt
571 spridda användningsområden. Användningsområdena som tagits upp i denna
572 rapport är enbart ett litet urval av de omfattande möjligheter som
573 Reguljära uttryck erbjuder. Vare sig man har använder sig av Reguljära
574 uttryck för att manipulera text direkt i en textredigerare eller om
575 man bygger in uttrycken i olika typer av applikationer och system så
576 erbjuder de Reguljära uttrycken nästintill oändliga möjligheter för
579 %. Använd minst två referenser utöver kursboken.
580 \bibliographystyle{alpha
}