Kapitel 8 Reguljära uttryck I kapitel 6 togs flera kommandon för texthantering upp. I detta tillkommer ett viktigt begrepp för texthantering reguljära uttryck. 8.1 Reguljära uttryck Vi har tidigare använt kommandot fgrep för att söka efter en textsträng. Ofta vill man göra mer avancerade sökningar än att bara söka efter en fix text. I många sammanhang går det att använda jokrar i stil med hur skalet gör för filnamn (s. 21), men en mycket mer kraftfull formalism som används i många sammanhang är reguljära uttryck. På engelska heter det regular expression vilket ibland kortas till bara regexp eller regex. I synnerhet kommer vi att använda sökkommandot egrep i uppgifterna. Ett reguljärt uttryck är ett mönster som beskriver en mängd strängar. T. ex. beskriver det reguljära uttrycket [Dd]at(a or)lingvistik strängarna»datalingvistik«,»datorlingvistik«,»datalingvistik«och»datorlingvistik«, men inga andra strängar. Vi säger att detta reguljära uttryck matchar dessa fyra strängar (och att dessa fyra strängar matchar detta reguljära uttryck). I detta exempel har tydligen tecknen []( ) speciell betydelse. 8.1.1 Metatecken De tecken som har speciell betydelse i reguljära tecken kallas för metatecken. Det finns olika varianter av reguljära uttryck med lite olika uppsättningar metatecken. Vanligt är att följande fjorton finns:. * +? ^ $ ( ) [ ] { } \ och det är reguljära uttryck med dessa som beskrivs nedan. 8.1.2 Ett godtyckligt tecken:. Punkten (.) matchar ett tecken vilket som helst. (Det fyller alltså samma funktion som frågetecken gör i jokeruttryck.) Så med b.x matchas»box«och»bmx«, samt även t. ex.»b%x«och»b x«. 8.1.3 Ett speciellt tecken: [ ] Om man ska beteckna ett tecken som man vill ställa mer krav på använder man hakparenteser. Genom att räkna upp tecken inom [] kan man ange ett av dessa tecken, så [Dd]ator matchar»dator«eller»dator«och [hmt]um[lm]a matchar»humla«,»humma«,»mumla«,»mumma«,»tumla«och»tumma«. Detta liknar hur man använder [] som jokertecken. Precis som då kan man även ange intervall, så [0-9] betyder samma som [0123456789]. Vill man ta med bindestrecket så får man sätta det först eller sist: [._-] matchar».«,»_«eller»-«. En skillnad är att i reguljära uttryck kan man använda ^ först för att negera en uppräkning av tecken, så [^aouå] matchar vilket tecken som helst som inte är a, o, u eller å och [^0-9] matchar vilket tecken som helst som inte är en siffra. 8.1.4 Teckenklasser Teckenklasserna från sidan 80 kan användas även inom [] i reguljära uttryck. Eftersom teckenklassernas namn innehåller egna hakparenteser blir det dubbla hakparenteser då. 91
8. REGULJÄRA UTTRYCK T. ex. matchar [8 [:upper:]!] ett tecken som är en åtta, ett mellanrum, en versal eller ett utropstecken. Ett reguljärt uttryck som ska matcha bara en versal blir [[:upper:]] med dubbla parenteser, medan t. ex. [^[:upper:][:digit:]_] matchar ett tecken som varken är versal, siffra eller understrykningstecken. 8.1.5 Repetitioner: + *? {} Med + efter något kan man säga att detta något ska förekomma en eller flera gånger. Det reguljära uttrycket bä+ matchar därmed strängarna»bä«,»bää«,»bäää«,»bääää«, osv., hur långt som helst. Observera att det bara är ä som repeteras. Detta reguljära uttryck matchar t. ex. inte»bäbäbä«. Asterisken * fungerar ungefär likadant, men tilllåter även att den»repeterade«delen inte är med någon gång alls. Så bä* matchar samma texter som bä+, men dessutom»b«. Blanda inte ihop denna användning av * med jokerbetydelsen! I reguljära uttryck betyder inte * nånting för sig själv, utan det modifierar bara det som står precis innan, så i ab*c modifierar det b och hela uttrycket matchar»ac«,»abc«,»abbc«,»abbbc«, osv. Genom att skriva.* kan man matcha vad som helst. Det betyder ju vilket tecken som helst, hur många gånger som helst. Därmed matchar t. ex. uttrycket a.*ö vad som helst som börjar med a och slutar med ö, t. ex.»adjö«,»atollö«eller»a4! ö«. Med? efter något anger man ett det är frivilligt, dvs. det kan vara med (en gång) eller inte. Så bä? matchar»b«och bä och inget annat. Med {n} efter något kan man säga att detta något ska förekomma n gånger. Så x{3} matchar»xxx«och [sz]{2} matchar»ss«,»sz«,»zs«och»zz«, dvs. samma som [sz][sz]. Med {n,m} ska det vara minst n och högst m förekomster, så br{2,5} matchar»brr«,»brrr«,»brrrr«och»brrrrr«, och inget annat. Maxantalet m kan utelämnas, och 8{3,} betyder minst tre åttor, dvs.»888«eller»8888«eller»88888«eller... (Hur många som helst.) 8.1.6 Parenteser: ( ) Med parenteser kan man föra samman ett större uttryck. Det gör t. ex. att (br){2,5} matchar»brbr«,»brbrbr«,»brbrbrbr«och»brbrbrbrbr«. Fler exempel: mo(no)+ton matchar»monoton«,»mononoton«,»monononoton«, osv. ([ptkbdg][aeiou]){3} matchar trestaviga ord där varje stavelse består av en klusil + någon av de angivna vokalerna, t. ex. bikupa, pitebo eller tekaka. Man kan ha parenteser inom varandra. Med ((ba)+r){3} matchas t. ex.»bababarbarbabar«,»barbarbar«och mycket mer. 8.1.7 Alternativ: Med lodstreck ( ) visar man alternativ. (Observera att detta motsvarar hur lodstreck används i syntaxen på man-sidor s. 58.) Så foo bar matchar»foo«och»bar«. Om man vill att bara en mindre del av uttrycket ska ha alternativ får man använda parenteser: f(oo ba)r matchar»foor«och»fbar«. 8.2 Ankring: ^ $ Metatecknen ^ och $ betyder början av raden respektive slutet av raden. Så med t. ex. ^xyz hittar man rader som börjar med xyz (radbörjan följt av»xyz«) och med [[:blank:]]$ hittar man rader som slutar med något blankt tecken. Dessa båda tecken matchar alltså inget tecken alls på egen hand, utan ställer bara krav på var det övriga i uttrycket ska befinna sig. Man säger att dessa ankrar ett reguljärt uttryck. 8.3 Bakstreck: \ Då återstår bara ett metatecken, nämligen bakstreck (\). Bakstrecket betyder nånting tillsammans med det tecken som följer direkt efter det. I synnerhet kan man sätta ett metatecken efter bakstreck när man verkligen vill söka efter det tecknet. Så för att söka efter t. ex. en siffra inom parenteser, som t. ex.»(3)«kan man använda det reguljära uttrycket \([0-9]\) med bakstreck för att visa att det verkligen ska vara med parenteser i texten. Detta kan användas även för bakstreck självt, så med \\ skriver man ett reguljärt uttryck som matchar ett bakstreck. 92
egrep I övrigt används bakstreck följt av annat tecken för lite olika funktioner. En sak som kan vara praktiskt är \w där»w«står för»word«. Det är synonymt med [[:alnum:]], dvs. ett alfanumeriskt tecken, men kortare att skriva. Med \< respektive \> matchar man en ordbörjan respektive ett ordslut. Liksom ^ och $ så matchar detta inte någon text i sig självt, men ger ett krav på var det som står runtomkring ska finnas. Så med \<anti hittar man»anti«som står i början av ett ord (t. ex.»anti«i»antites«eller»antilop«men inte i»fantisera«) och med \<\w\w\> hittar man ett ord med exakt två bokstäver. 8.3.1 Exempel Här är några ytterligare exempel på reguljära uttryck. [a-h][1-8] en ruta på ett schackbräde, som»e2«eller»b4«. [0-9]*[02468] en sekvens med siffror som slutar med en jämn siffra (fjor fem sex sjut ar nit)ton tjugo något av orden fr. o. m.»fjorton«t. o. m.»tjugo«(..)* ett jämnt antal tecken, vilka som helst \<pre\w*ing\> ett ord som börjar med»pre«och slutar med»ing«. uttryck behöver man ofta sätta det argumentet inom citattecken som ovan. Det kan vara säkrast att ha som vana att göra det. 8.4.1 Väljare till egrep Det finns många väljare till kommandot egrep. 1 Några av de mest användbara är: -c Ge inte raderna som output utan bara hur många rader som innehåller något som matchar det reguljära uttrycket (count) -i Ignorera (ignore) skillnader mellan stora och små bokstäver -v Motsatsen. Lista de rader som inte innehåller något som matchar det reguljära uttrycket Tänk på att egrep liksom många andra textbearbetningskommandon är radorienterad. Det man får ut är vilka rader som innehåller den söktatexten. Det innebär att om man gör en sökning som egrep 'karakt[eä]ristisk' FIL och får ut fem rader så betyder inte det nödvändigtvis att ordet»karaktäristisk«(eller»karakteristisk«) förekommer fem gånger i filen, utan att det finns fem rader som innehåller den texten. Några av dessa rader innehåller kanske flera förekomster av texten! 8.4 egrep Förut har vi använt fgrep för att leta efter en text. Med egrep ska det första argumentet istället vara ett reguljärt uttryck. Eventuella övriga argument är namn på filer att leta i, men om inga ges så söker egrep istället i standard input, precis så som fgrep gör. Som output kommer alla rader i inputten som innehåller något som matchar det reguljära uttrycket. Exempel: $ tail -n 20 FIL egrep 'x[0-9]+x' Finns det i de sista 20 raderna i filen FIL två x som bara innehåller en eller flera siffror mellan sig? Lista i så fall de rader där detta finns med. Eftersom man ofta har med tecken som skalet tolkar speciellt (t. ex. som jokrar!) i sina reguljära 1 Alla dessa finns till fgrep också. 93
Laboration 8: Reguljära uttryck och textbehandling Redovisning Skriv en article i LaTeX där du svarar på frågorna. Utgå från mallen i /local/kurs/ids/ labb8-mall.tex där det även finns ytterligare instruktioner som kommentarer. Svara på frågorna. När du ger kommandon för att få fram svaret så visa både kommandona och deras resultat. Använd omgivningen verbatim för sådant. Det ideala är om du har ett kommando som bara ger svaret och inget annat så att du inte behövde se igenom mycket output och plocka ut svaret därifrån för hand. Skicka datorpost till Per med LaTeX-filen senast måndagen den 12/11. När filer nämns med bara ett namn så ligger de i /local/kurs/ids/. Exempeluppgifter Dessa är redan lösta i mallen! Uppgift 8.1 Vilka rader i filen /local/kurs/ids/ ivt2-svenska.txt innehåller ord som slutar med»gn«? Uppgift 8.2 Vad betyder {3,5} i ett reguljärt uttryck? Ge exempel. Uppror! I uppgift 4.40 på s. 54 sparade du en version av uppror.txt med normal Unix-markering för nyrad. Den ska du använda nu. (Öppna den för säkerhets skull i Emacs och se att inte står (DOS) eller (Mac) i informationsraden vilket skulle visa att den har annan markering av nyrad.) Alla uppgifter i detta avsnitt använder sig av den filen. Uppgift 8.3 Vilka rader innehåller två y med exakt två tecken mellan sig? Uppgift 8.4 Vilka rader innehåller ett c som följs av l, u eller y? Uppgift 8.5 Vilka rader innehåller ett z som följs av något annat än o eller s? Uppgift 8.6 Vilka rader innehåller en labial konsonant (någon av p, b, m, f eller v) följt av el följt av antingen ett h eller interpunktion? Uppgift 8.7 Vilka rader innehåller en liten bokstav som följs direkt av en stor? Uppgift 8.8 Vilka rader innehåller minst fyra siffror i rad? Uppgift 8.9 Hur många rader innehåller minst tre interpunktionstecken i rad? Uppgift 8.10 Vilka rader har minst sex konsonanter i rad? Uppgift 8.11 Ordet kriminalisera innehåller sex alterneringar av konsonant + vokal i rad (ri-mi-na-lise-ra). Vilka rader i uppror.txt innehåller också sex sådana alterneringar? Uppgift 8.12 Vilka rader innehåller något av orden mitt, ditt, sitt, hans, hennes följt av ett mellanslag och sedan ordet liv? Uppgift 8.13 Vilka rader börjar med bokstaven y? 95
LABORATION 8: REGULJÄRA UTTRYCK OCH TEXTBEHANDLING Uppgift 8.14 Vilka rader börjar med ordet kan? Uppgift 8.15 Vilka rader har bokstaven d som andra tecken? Uppgift 8.16 Vilka rader både börjar och slutar med bokstaven m? Uppgift 8.17 Vilka rader både börjar och slutar med bokstaven m, men har inga ytterligare m i sig? Uppgift 8.18 Vilka rader har med ord som börjar med»flä«? Uppgift 8.19 Hur många rader är minst femtio tecken långa? Uppgift 8.20 Hur många rader innehåller inte något interpunktionstecken? 8ttorna igen I detta avsnitt letas efter ord i 8.list från s. 83. Uppgift 8.21 Hur många ord innehåller q eller z (eller båda)? Uppgift 8.22 Vilka ord innehåller både q och z så att q kommer före z? (Inte nödvändigtvis omedelbart före, så t. ex. ska squeezed bli ett av orden i svaret.) Uppgift 8.23 Vilka ord börjar med fyra konsonanter? (Räkna inte y som konsonant, trots att den ofta är det på engelska.) Uppgift 8.24 Vilka ord innehåller delsträngen ma två gånger med minst ett tecken mellan de båda förekomsterna? Ord som smalfilma och hemmamatch skulle alltså komma med, ifall de hade stått med i denna ordlista. Uppgift 8.25 (Korsord) Vi söker ett åttabokstavigt ord. Första bokstaven måste vara m, p eller v. Andra bokstaven är säkert ett o. Sista bokstaven är o eller p. Vad kan det vara för ord? Uppgift 8.26 Vilka ord innehåller inte någon av bokstäverna i»etaoin«? (De vanligaste bokstäverna i engelska.) Uppgift 8.27 Hur många ord innehåller minst två b (inte nödvändigtvis direkt efter varann)? Mer mer mer Uppgift 8.28 Ge ett reguljärt uttryck som matchar orden»mormor«,»morfar«,»farmor«och»farfar«. Här är mormor morfar farmor farfar förstås en möjlighet, men försök att skriva något kortare! Uppgift 8.29 Ge ett kort reguljärt uttryck som matchar både»arton«och»aderton«(men inget annat). Uppgift 8.30 Det reguljära uttrycket ab?c[de] beskriver strängarna»acd«,»ace«,»abcd«och»abce«. Vilka strängar beskriver följande reguljära uttryck? (Ange samtliga strängar!) a) rök?fritt b) a b? c c) fo{4,6}l? d) ([abc]-)?foo e) foo(bar?)? Uppgift 8.31 Ge ett reguljärt uttryck som matchar något av»1«,»2«,»3«,»4«,»5«,»6«,»7«,»8«,»9«,»10«,»11«,»12«,»13«osv. till hur höga tal som helst, men inget annat. (Första siffran är speciell!) Uppgift 8.32 Skriv ekvivalenter till följande regexpar som är så korta som möjligt: a) [abc][abc][abc][abc][abc][abc]? b) colour color c) (a b c d e) d) (ha he hi ho) e)..+.. f) x.*.*y Uppgift 8.33 De tre metatecknen *, + och? som kan sättas efter en del av ett reguljärt uttryck kan alla uttryckas med {}-konstruktionen istället. Hur, i de tre olika fallen? Visa dessa ekvivalenser i en tabular. 96
Mer mer mer Uppgift 8.34 Lista första halvan av varje ord i 8.list vars andra halva är mark. Så eftersom det finns ett ord landmark ska land finnas med i ditt resultat, t. ex. Uppgift 8.35 Vilka rader i rummet.words är substantiv som innehåller u? Uppgift 8.36 Hur många fyrbokstavssträngar finns det som förekommer både som förstahalva och som andrahalva i 8.list? (Dit hör t. ex.»poly«som finns både i monopoly och ord som polygamy.) Uppgift 8.37 Vilka ord som finns med i texten wonderland.txt slutar på»rd«? Uppgift 8.38 (Korta Strindbergord) Ge en frekvenslista över ord med högst tre bokstäver i rummet.txt. Ta bara med ord som förekommer minst två gånger. 97