Kapitel 8 Reguljära uttryck I kapitel 6 togs reguljära uttryck upp som argument till grep. I detta kapitel lär vi oss mer om sådana och om några andra sammanhang där de används. På engelska heter det regular expression vilket ibland kortas till bara regexp eller regex. Även på svenska talar man ofta om regexpar. 8.1 Ett tecken:. [ ] [^ ]. = ett godtyckligt tecken [abc] = något av tecknen a, b eller c [^abc] = ett tecken som inte är a, b eller c Inom hakparenteser kan - användas mellan två tecken för intervall. Så [0-9] betyder 0, 1, 2, 3, 4, 5, 6, 7, 8 eller 9, och [0-9,.] betyder 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, komma eller punkt. De flesta tecken som är speciella annars i regexpar är inte speciella inom []. T. ex. matchar [9.*] en nia eller en punkt eller en asterisk. (Utanför hakparenteserna hade båda punkten och asterisken haft en särskild betydelse.) Dessutom kan man inom [] stoppa in en beteckning för en hel klass tecken, som betyder t. ex.»en bokstav«eller»ett skiljetecken«. Dessa teckenklasser har namn som börjar med [: och slutar med :], t. ex. [:lower:] för en gemen bokstav. Tabell 8.1 visar några av dessa. Traditionellt har man skrivit t. ex. [A-Z] för att få en versal, och detta (och [a-z] och [A-Za-z]) kan man se på många håll i exempel på reguljära uttryck. Det är dock säkrare att använda namngivna klasser. Då ska man få man med alla bokstäver, även Tabell 8.1: Några namngivna teckenklasser. Betydelserna är inte helt strikta här, utan kan variera med olika locale. Namn [:alnum:] [:alpha:] [:blank:] [:cntrl:] [:digit:] [:graph:] [:lower:] [:print:] [:punct:] [:upper:] Betydelse Alfanumeriska: [:alpha:] + [:digit:] Bokstäver: [:lower:] + [:upper:] Blanka tecken (mellanrum och TAB) Kontrolltecken Siffror Grafiska: [:alnum:] + [:punct:] Gemena (små) bokstäver Skrivbara: [:graph:] + mellanrum Interpunktion Versala (STORA) bokstäver t. ex. åäö, oavsett språkinställningar. 1 Observera att hakparenteserna ingår i namnen på dessa teckenklasser! Det gör att det blir dubbla hakparenteser i de reguljära uttrycken. Om man byter ut A-Z mot [:upper:] så betyder det att ett reguljärt uttryck som [A-Z] istället blir [[:upper:]], medan [^A-Z] blir [^[:upper:]], och uttrycket [z[:punct:] ] betyder ett z eller ett interpunktionstecken eller ett mellanslag. 8.2 Ankring: ^ $ \< \> Metatecknen ^ och $ för början av raden respektive slutet av raden har vi redan sett. Så med t. ex. ^xyz hittar man rader som börjar med xyz (radbörjan följt av»xyz«) och med 1 Skriv inte [a-ö] när du menar en bokstav! Dels skulle det vara beroende av en viss sorteringsordning, och dessutom funkar det ändå inte som man skulle kunna tro. 83
8. REGULJÄRA UTTRYCK [[: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. Med \< respektive \> matchar man en ordbörjan respektive ett ordslut. 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«). 8.3 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 mellan asterisker, 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 asterisker i texten. I övrigt används bakstreck följt av annat tecken för lite olika funktioner. Under ankring ovan nämndes två. En annan användbar är \w där»w«står för»word«. Det betyder liksom [[:alnum:]] ett alfanumeriskt tecken, men är kortare att skriva. Så a\wa matchar t. ex.»axa«och»a7a«, men inte»a!a«. 8.4 Utökade reguljära uttryck Det finns olika varianter av reguljära uttryck med lite olika uppsättningar metatecken. Hittills har vi sett enkla reguljära uttryck (basic regular expressions) där de speciella tecknen är. * ^ $ [ ] \ Med så kallade utökade reguljära uttryck (extended regular expressions) tillkommer dessa: +? ( ) { } Kommandot grep använder normalt de enkla (basic) regexparna, men med en väljare -E (som i Extended) använder den de utökade. 8.5 Repetitioner: * +? {} Asterisken har vi sett förut. Nytt i de utökade regexparna är + efter något för att säga att detta något ska förekomma en eller flera gånger. Det utökade 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ä«.) Skillnaden med asterisken * är att den även tilllåter att den repeterade delen inte är med någon gång alls. Så bä* matchar samma texter som bä+, men dessutom även»b«. Med? efter något anger man ett det är frivilligt, dvs. det kan vara med en gång eller inte alls. 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å [sz]{3} matchar samma som [sz][sz][sz], dvs.»sss«,»ssz«,»szs«,»szz«,»zss«,»zsz«,»zzs«och»zzz«. 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.) Om inte det som står före det som visar repetition är något inom [] eller () (som vi kommer till snart!) så är det ett ensamt tecken som repeteras. Så hej?hopp matchar»hejhopp«eller»hej hopp«. 8.6 Alternativ: Med lodstreck ( ) visar man alternativ. Så vit svart grå matchar»vit«eller»svart«eller»grå«och foo b[aä]r matchar»foo«eller»bar«eller»bär«(eftersom alternativet efter lodstrecket hade två varianter). Glöm inte att hakparenteser kan användas om alla alternativ består av ett tecken, så istället för a e i o u är det enklare att skriva [aeiou]. 8.6.1 Parenteser: ( ) Med parenteser kan man föra samman ett större uttryck. Så med en (grå liten stor) katt matchar man»en grå liten katt«eller»en stor katt«. Utan parenteser skulle det bli allt före eller efter lodstrecket. Parenteser är också användbara för att hålla ihop något som ska repeteras. Det gör t. ex. att 84
8.9. Reguljära uttryck i Emacs (bar){2,5} matchar»barbar«,»barbarbar«,»barbarbarbar«och»barbarbarbarbar«. Fler exempel: en (grön blå)+ kavaj matchar t. ex.»en grön kavaj«eller»en blågrön kavaj«eller»en gröngrön kavaj«eller»en blåblågrönblågrön kavaj«. en grön blå+ kavaj vore däremot något helt annat! Det skulle matcha antingen»en grön«eller också något som matchas av blå+ kavaj, dvs.»blå kavaj«eller»blåå kavaj«eller»blååå kavaj«osv. mo(no)+ton matchar»monoton«,»mononoton«,»monononoton«, osv. 8.7 Exempel Här är några ytterligare exempel på utökade reguljära uttryck [a-h][1-8] en ruta på ett schackbräde, som»e2«eller»b4«. [0-9]*[13579] en sekvens med siffror som slutar med en udda siffra, som t. ex.»4711«eller»007«. (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«. ^[^ ].* $ en rad som börjar med något annat än mellanslag och som slutar med mellanslag. 8.8 Olika sorters reguljära uttryck Reguljära uttryck används inte bara av grep utan dyker upp i flera sammanhang. Av historiska skäl används dock tyvärr flera olika varianter av reguljära uttryck. Ibland används de utökade (som grep -E använder), ibland de enkla (som grep använder normalt) där tecknen +? ( ) { } inte har någon särskild betydelse, utan betyder sig själva. (En del program som använder reguljära uttryck har dessutom sina egna utökningar av dem. Det har t. ex. Emacs och programspråket Perl. Flera utökningar som har gjorts för Perl har plockats över till andra sammanhang också, t. ex. programspråken Java och Python.) I grep så kan man komma åt all funktionalitet som man kan få med +? ( ) { } utan att gå över till utökade reguljära uttryck genom att skriva \+ \? \( \) \{ \} \ istället. Så dessa två kommandon gör samma sak: $ grep -E "^(tre fyr fem)" verb.txt trefaldiga femfaldiga fyrfaldiga tredska tredubbla fyrdubbla tremulera trepanera fyra treva $ grep "^\(tre\ fyr\ fem\)" verb.txt [ samma svar ] nämligen hittar de rader i den filen som börjar med»tre«,»fyr«eller»fem«. 8.9 Reguljära uttryck i Emacs Det finns flera kommandon i Emacs som använder reguljära uttryck. Vid sidan av C-s och C-r som söker framåt respektive bakåt efter en textsträng så finns även C-M-s och C-M-r som söker framåt respektive bakåt efter ett reguljärt uttryck. (Här ska alltså både Control och Meta användas tillsammans.) Under en inkrementell sökning kan man också använda M-r för att slå om huruvida sökningen ska gälla reguljära uttryck eller inte. Det finns även andra kommandon som ni kommer att möta i labben. De reguljära uttrycken i Emacs är ungefär som enkla reguljära uttryck, men även plustecknet och frågetecknet är metatecken. 8.10 grep -o Kommandot grep arbetar som många andra kommandon normalt med rader. Den fungerar som ett filter som bara släpper igenom de rader som innehåller ett visst sökuttryck. (Eller med väljaren -v de rader som inte innehåller ett visst sökuttryck.) 85
8. REGULJÄRA UTTRYCK Med väljaren -o ändras detta och man får istället ut just de delar som matchade sökuttrycket istället för hela rader. $ grep l.ll verb.txt lalla lulla parallellställa parallellisera $ grep -o l.ll verb.txt lall lull lell lell Se sökningarna i figur 8.1 där vi söker efter ord som börjar på»f«. Utan -o spelar det ingen roll om vi söker efter \<f\w* eller bara \<f. Det är samma rader (i detta fall bara en rad) som hittas. Men med \w* på slutet hittas hela ordet, vilket gör skillnad när vi använder -o för att få se vilken del av texten som matchade sökuttrycket. Det kan (som här) bli flera matchningar per rad. 8.11 Girighet och hunger Ett sådant uttryck som [1-9]0* matchar ju en siffra 1 9 eventuellt följt av nollor, t. ex.»5«,»10«eller»30000«. $ echo 'Timmy 2000' grep -o '[1-9]0*' 2000 egentligen hade tänkt sig. Om man t. ex. vill söka efter citat inom»«kan det ligga nära till hands att använda ett reguljärt uttryck».*«för att visa att det ska börja med», sluta med «och däremellan får innehålla vad som helst. Men»vad som helst«kan bli mer än man tänkt sig: $ cat testfil Hej hopp! Ska det stå»i dag«eller»idag«? $ grep -o '».*«' testfil»i dag«eller»idag«detta svar börjar ju och slutar med de efterfrågade tecknen, men är längre än bara»i dag«som man kanske snarare var ute efter. I detta fall är ett sätt att lösa problemet att kräva att tecknen mellan de båda citattecknen inte själva får vara slutcitattecken, dvs. att använda [^«] istället för. för varje tecken mellan citattecknen. $ grep -o '»[^«]*«' testfil»i dagidag«8.12 sed Med kommandot sed kan man göra en mängd olika omvandlingar av text. Namnet står för stream editor. Det kan göra mycket som en editor kan göra, I exemplet ovan ser vi hur uttrycket matchade»2000«. Men det skulle ju också kunna ha matchat bara»200«eller»20«eller»2«. Ändå är det just matchningen»2000«som vi fick fram. Vid matchningen väljs nämligen den längsta av flera möjligheter som börjar på samma plats. Man säger att operatorn * här är girig eller hungrig (greedy på engelska) vilket innebär att den»vill«matcha så mycket som möjligt. Samma gäller de andra repetitionsoperatorerna vi har tagit upp. Detta behöver man tänka på ibland, i synnerhet med.* eller.+ som lätt kan matcha mer än man ed och sed: Den ursprungliga editorn på Unix, som användes redan i forntiden före bildskärmarnas tid, hette ed och var skriven av Ken Thompson. Det var Thompson som först introducerade reguljära uttryck i editorer. När kommandot sed kom några år senare som en variant att använda för icke-interaktiv editering av en inputström så byggde därför dess kommandon på motsvarande kommandon i ed. Det enda sed-kommando vi tar upp här, s, finns t. ex. även i ed. 86
8.12. sed $ grep "\<f" saga.txt ingenting, för han var försäkrad. Några dagar senare flyttade $ grep -o "\<f" saga.txt f f f $ grep "\<f\w*" saga.txt ingenting, för han var försäkrad. Några dagar senare flyttade $ grep -o "\<f\w*" saga.txt för försäkrad flyttade Figur 8.1: Greppande med och utan -o i en saga. \<f betyder ett f i början av ett ord, och \w* betyder godtyckligt många ytterligare»ordtecken«efter det, så tillsammans betyder det ett ord som börjar på f. men gör det inte interaktivt utan genom att bearbeta text som kommer in i en inputström. Detta kan läggas in som ett avancerat filter som läser text från standard input och skriver ut en editerad version av texten på standard output. Kommandot sed är lite som en schweizisk armékniv som kan utföra en mängd olika saker, bland annat sådant som ni har använt andra kommandon till, som head, tail och tr. Här kommer vi dock att bara använda detta kraftfulla verktyg till en specifik sak, nämligen att byta ut text. 8.12.1 Att ersätta text med sed Tidigare har vi använt tr för att byta ut text, men det är begränsat genom att det bara är enstaka tec- Varför heter det grep?: I editorn ed användes reguljära uttryck inte bara med kommandot s, utan även med bl. a. ett kommando g med vilket man sökte upp rader som matchade ett visst reguljärt uttryck och gjorde nåt med dessa rader. För att ta bort alla rader som innehåller»foo«kunde man t. ex. göra g/foo/d där d är ett kommando som tar bort en rad. För att skriva ut alla rader som matchade ett reguljärt uttryck använde man istället p (= print). Ibland förkortas regular expression med re, så en sådan operation kunde beskrivas g/re/p vilket är skälet till att det senare skrivna program som utförde just den operationen fick namnet grep. ken som hanteras. Det duger inte om vi t. ex. vill byta ut alla förekomster av»foo«mot»bar«. Dessutom har det begränsningar vid hantering av flerbytestecken. Eftersom ni nu bara kommer att använda sed till en sak så kommer alla era anrop av sed att likna varandra. De kommer alla att se ut ungefär som sed 's/regexp/replacement/g' Här är det bara ett argument till sed, och det talar om vilken editering som ska utföras. Det s som argumentet börjar med här är ett kommando i sed för substitute. Det söker upp förekomster av text som matchar det reguljära uttrycket regexp och byter ut dessa mot texten replacement. Så t. ex. kan man skriva sed 's/color/colour/g' för att byta ut alla»color«mot»colour«. 2 eller sed 's/s\>/z/g' för att byta ut varje s som står i slutet av ett ord mot z. Man brukar normalt använda snedstreck (/) som här för att avdela argumentet, men det kan vara något annat tecken istället, bara det är samma tecken på alla tre ställen. Så om man behöver snedstreck i 2 I detta fall behövdes inte några citattecken runt argumentet till sed, eftersom inga tecken där är speciella i skalet, men oftast behövs det, så det kan vara säkrast att alltid ha med det. 87
8. REGULJÄRA UTTRYCK sitt reguljära uttryck eller i ersättningen får man lov att välja nåt annat, t. ex. sed 's!1/2!½!g' för att byta alla förekomster av de tre tecknen»1/2«mot det enda tecknet»½«. Efter det sista snedstrecket står väljare till s- kommandot. I exemplen ovan är det g som gör att alla förekomster byts ut (global). Annars byts bara den första förekomsten på varje rad ut. En annan väljare är i som ignorerar skillnader mellan versaler och gemener. Jämför följande fyra exempel som bara skiljer sig i vilka av dessa väljare som har använts. Om man ger ett andra argument till sed så är det vilken fil den ska hämta input från. Ett tecken som ändå är speciellt i ersättningstexten är & (ampersand) som betyder hela den text som matchade det reguljära uttrycket. Om man vill bryta raden efter varje interpunktionstecken kan man därför göra sed 's/[[:punct:]]/&\n/g' där ersättningsdelen betyder det som [[:punct:]] matchade följt av ett nyradstecken (vilket skrivs \n här precis som t. ex. i tr). Följande exempel dubblerar vokaler genom att använda ampersand två gånger. sed 's/[aeiouyåäö]/&&/gi' $ cat jaha.txt Procent procent procent PROCENT $ sed 's/procent/%/' jaha.txt Procent % procent PROCENT $ sed 's/procent/%/g' jaha.txt Procent % % PROCENT $ sed 's/procent/%/i' jaha.txt % procent procent PROCENT $ sed 's/procent/%/gi' jaha.txt % % % % Kommandot sed använder normalt enkla reguljära uttryck, men har en väljare -r som gör att den istället använder utökade reguljära uttryck. 8.12.2 Att återanvända originaltexten I sed 's/regexp/replacement/g' är det bara regexp som är ett reguljärt uttryck. I ersättningsdelen har inte asterisker, parenteser osv. någon särskild betydelse, utan blir sig själva. $ echo 'byt allt' sed 's/././g'... $ echo 'foo bar' sed 's/[aou]/[äöü]/g' f[äöü][äöü] b[äöü]r $ echo 'hej hopp' sed 's/e.*o/***/g' h***pp 88
Laboration 8: Reguljära uttryck Redovisning Skicka svar på frågorna till Per senast måndag 2/11. Frågorna är samlade i olika teman snarare än att vara sorterade från lätta till svåra, så hoppa gärna runt bland uppgifterna medan du löser dem istället för att fastna på någon klurig uppgift som du kan behöva tänka mer på. När frågan är i stil med»vilka ord finns det som...?«så ge dels svar på frågan och tala dels om vilket kommando eller vilka kommandon du använt för att få fram svaret. På slutet följer en del överkursuppgifter som är frivilliga. Om du bara kan lösa en uppgift till hälften så ge din lösning ändå, men påpeka vad som saknas i den. Svenska ord I /local/dict/dsso-list.txt finns en stor samling svenska ordformer tagna från Den stora svenska ordlistan. Använd den för frågorna i detta avsnitt. 3 Eftersom filen bara innehåller ord med ett ord per rad kan du använda ^ och $ för ankring till ordbörjan och ordslut och. för ett godtyckligt tecken inne i ordet. Uppgift 8.1 Hur många ord finns det som slutar på bokstaven v? Uppgift 8.2 Hur många ord finns det som innehåller»stp«i sig (som t. ex.»festprisse«) och hur långt är det längsta av dessa ord? 3 Detta kommer från Den stora svenska ordlistan på http: //dsso.se/ ett projekt för att göra en fri svensk ordlista över nätet. Ett sätt att ta fram orden i listan som börjar med v och slutar med p är med kommandot grep "^v" dsso-list.txt grep "p$". Här tar man först fram de rader som börjar med v och sen från det resultatet filtrerar man fram de rader som dessutom slutar med p. Uppgift 8.3 Det går även även att lösa denna uppgift med bara ett grep-kommando genom att skriva ett reguljärt uttryck som för in båda kraven samtidigt, men tillåter vad som helst däremellan. Hur? Uppgift 8.4 Vad finns det för ord som innehåller minst tre ä, som t. ex.»självbestämmanderätt«? Uppgift 8.5 Vilka ord med minst nio bokstäver går att skriva enbart med tecknen på översta bokstavsraden på tangentbordet? (qwertyuiopå) Uppgift 8.6 (Monoton) Vad finns det för ord som är minst 12 tecken långa vars enda vokal är o? Uppgift 8.7 (korsord) Du söker ett elvabokstavsord som börjar på f eller r och slutar på a eller t. Den fjärde bokstaven är säkert m och den sjunde är säkert i. Vad finns det för möjligheter (om ordet står med i denna ordlista)? Uppgift 8.8 Vilka ord med minst fem tecken har inte med någon av bokstäverna eantrsildogm? (De vanligaste tecknen på svenska enligt någon källa.) Uppgift 8.9 En del ord i den filen innehåller tecken som inte räknas som ingående i teckenklassen [:alpha:]. Hur många ord? 89
LABORATION 8: REGULJÄRA UTTRYCK Väljaren -o I dessa uppgifter ska du använda väljaren -o för att bara få ut det som matchar ett uttryck från en fil. Uppgift 8.10 Vilka tecken var det som fanns med i ordlistan trots att de inte i [:alpha:] i förra uppgiften Uppgift 8.11 Vilka ord i /local/kurs/ids/ wonderland.txt börjar med»cal«? (Rensa bort dubbletter från ditt svar.) Uppgift 8.12 Vad finns det för ord som börjar med versal och slutar med k i samma fil? Använd \w för att beteckna ett tecken inne i ett ord, och rensa bort dubbletter från ditt svar. Uppgift 8.13 Vad finns det för ord som innehåller q i samma fil? (Rensa bort dubbletter från ditt svar.) Uppgift 8.14 Använd det utökade reguljära uttrycket [0-9]+ för att ta fram vilka sifferuttryck som finns i filen /local/kurs/ids/the-gnu-project och sortera dem i nummerordning. Uppgift 8.15 Skapa en fil GNU-words2 som listar alla ord i filen GNU. Använd denna gång grep -o med lämpliga argument för att plocka ut orden och rensa bort dubbletter. På vilka sätt blev denna ordlista bättre än den GNU-words som du skapade i uppgift 6.36 (s. 79)? Uppgift 8.16 Ge en frekvenslista över ord med exakt tre bokstäver i rummet.txt. Ta bara med ord som förekommer minst två gånger. En sluttagg i HTML börjar ju med»</«och slutar med»>«. Prova därför med grep -o "</.*>" ~ellen/public_html/saga.html för att ta fram sluttaggar från denna HTML-fil. Uppgift 8.17 En del rader i svaret blev verkligen sådana, t. ex.»</head>«, men andra rader kom att innehålla mer. Vad är problemet? Hur kan du fixa det? Ge ett sorterad lista (utan dubbletter) med alla sluttaggar som förekommer i den filen. Uppgift 8.18 Ta med grep -Eo och lämpliga argument fram telefonnummer med riktnummer från tidningstexterna i /local/kurs/ids/ ivt2-svenska.txt. Din lösning kan vara mer eller mindre bra. Ju fler korrekta nummer du får ut desto bättre, men undvik att få falska träffar med sifferuttryck som inte är telefonnummer. To -v or not to -v? Vad finns det för verb som inte innehåller a? Det handlar alltså om rader i verb.txt som inte innehåller tecknet a. Ett sätt att skriva ett reguljärt uttryck som börjar med radbörjan, slutar med radslut och talar om att varenda tecken däremellan måste vara ett icke-a. $ grep '^[^a]*$' verb.txt Uppgift 8.19 Denna uppgift går dock lättare att lösa med hjälp av grep-väljaren -v. Hur? Här är ett annat exempelkommando: $ grep -v '[^äö]$' verb.txt Uppgift 8.20 Hur kan du skriva ett grepkommando utan -v som gör samma sak som detta? Ta sed dit man kommer Uppgift 8.21 (Stavningsreform) Skriv ett sedkommando som byter ut alla»ck«mot»kk«. Du kan prova ditt kommando med t. ex. ditt kommando ck-test.txt där ck-test.txt är en fil som du gjort med lite testord, eller typ echo sicksack ditt kommando. Uppgift 8.22 Hur lyder din saga på i-sprikit (även kallat i-språket), dvs. med alla vokaler utbytta mot i. Svaret ska börja»dit vir in ging«. Uppgift 8.23 Hur lyder din saga om alla mellanslag byts ut mot dubbla mellanslag? Svaret ska alltså börja Det var en gång. 90
Mer mer mer Uppgift 8.24 Om Strindberg hade behövt skriva Roeda rummet på en engelsk skrivmaskin och fått lov att skriva aa ae oe istället för å ä ö, hur hade då början av den lydit? Uppgift 8.25 Skriv ett kommando som byter ut alla ord»ej«mot»icke«i en text. Se till att du bara byter ut hela ord så att du inte råkar byta t. ex.»mejl«mot»mickel«. Uppgift 8.26 Skapa en fil GNU2 i din ids-katalog som är som GNU, men där du lagt till»<abbr>«före och»</abbr>«efter varje ord som är minst två bokstäver långt och som bara består av versaler. Så t. ex. ska varje förekomst av ordet»mit«ha bytts mot»<abbr>mit</abbr>«. I Emacs Öppna filen /local/kurs/ids/wonderland.txt i Emacs. Det finns ett Emacs-kommando som heter occur som listar de rader som innehåller text som matchar ett visst reguljärt uttryck. Detta kommando finns dock inte i menyerna. För att ge ett Emacskommando som man kan namnet på kan man trycka M-x (Meta-x) och sen skriva kommandot i minibufferten, följt av RET. Gör så! Du får sen skriva ett ett reguljärt uttryck. Skriv side\> för att lista rader som innehåller ord som slutar på»side«. Uppgift 8.27 Hur många matchingar blev det och hur visas dessa? Sökträffarna visas i en buffert som är i ett särskilt Emacsläge där man kan gå direkt till en träff genom att klicka på den, eller genom att trycka på RET. Uppgift 8.28 När man ger ett kommando med M-x i Emacs får man ett meddelande i ekoarean om hur man också hade kunnat ge kommandot om det finns ett kortkommando för det. Med vilka tangenttryckningar hade man också kunnat ge kommandot occur? Använd nu Tools Search Files (Grep) i samma Emacs. I minibufferten får du ett påbörjat grepkommando. Lägg till gren *.txt till det för att leta efter»gren«i alla filer *.txt i den katalogen (/local/kurs/ids). Här kan du på ett liknande sätt använda musklick eller RET för att gå till sökträffarna. Uppgift 8.29 En av de väljare som användes till grep-kommandot här var -n. Den har vi inte använt i kursen. Vad betyder den? Uppgift 8.30 En av träffarna är från filen nordic-authors.txt. Vilken författare var det som hittades där? Mer mer mer Uppgift 8.31 Vilka tecken är metatecken i enkla reguljära uttryck? Uppgift 8.32 Hur lyder din saga.txt om man tar bort alla vokaler? (Svaret ska alltså börja»dt vr n gng«.) Uppgift 8.33 Hur lyder din saga.txt om alla bokstäver dubbleras? (Svaret ska alltså börja»ddeett vvaarr eenn ggåånngg«. Bara bokstäverna är dubblerade, men inte mellanslag eller interpunktion.) Uppgift 8.34 Hur lyder din saga.txt om sista bokstaven i varje ord tas bort? (Svaret ska alltså börja»de va e gån«.) Uppgift 8.35 Hur lyder din saga.txt om alla versaler sätts inom hakparenteser? (Svaret ska alltså börja»[d]et var en gång«.) Uppgift 8.36 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.37 Ge ett kort utökat reguljärt uttryck som matchar både»arton«och»aderton«(men inget annat). En möjlighet är helt enkelt arton aderton, men gör något kortare! Uppgift 8.38 Ge ett utökat reguljärt uttryck som matchar orden»mormor«,»morfar«,»farmor«och»farfar«(men inget annat). Här är mormor morfar farmor farfar förstås en möjlighet, men försök att skriva något kortare! 91
LABORATION 8: REGULJÄRA UTTRYCK Uppgift 8.39 Här ges ett antal utökade reguljära uttryck som alla går att skriva kortare så att ändå exakt samma texter matchas. Hur? a) foo* b) bar{1,} c) Svenson Svensson d) [[:alnum:]]{0,1} e) ((kan)(a e y)l) f) (0 1 2 3 4) g) (ha he hi ho) h) [aouå] [eiyäö] i) (godmorgon godkväll), kamrater j) [abc][abc][abc][abc][abc][abc]? k) x.*.*y Bakåtreferenser Hela detta avsnitt är frivillig överkurs. Läs om bakåtreferenser (back-references) i reguljära uttryck 4 och använt sådant för att lösa följande. Uppgift 8.40 Vilka ord i /local/dict/ dsso-list.txt består av två likadana halvor (som t. ex. orden»kaka«och»mormor«)? Uppgift 8.41 Vad finns det för sjubokstavsord i samma fil som är palindrom? (Palindrom är sådana texter som lyder likadant framlänges som baklänges, som t. ex. kajak.) Uppgift 8.42 Vilka ord i samma fil har högst åtta bokstäver och har två dubbeltecknade bokstäver i rad, så som t. ex.»rättssal«. Uppgift 8.43 Använd sed för att lösa om uppgiften med att vända ordningen på us-states.txt från överst på s. 70. Uppgift 8.44 Tänk dig att en text har använt decimalpunkt istället för decimalkomma, dvs. där står t. ex.»3.14«istället för»3,14«, men det ska ändras till decimalkomma. Skriv ett sed-kommando som byter ut sådana punkter som står mellan två siffror till komman (men inte byter ut andra punkter!). 4 T. ex. i Info-dokumentationen om grep. 92