next up previous contents
Nästa: 10.2 Redigering i förbifarten Upp: 10. Textbehandling Förra: 10. Textbehandling

10.1 Reguljära mönster

I grep och flera andra UNIX-program används något som kallas för reguljära mönster. Syftet med reguljära mönster är helt enkelt att matcha text. Tekniken liknar den som skalet använder för att matcha filnamn, men den är mycket kraftfullare. De följande sidorna beskriver hur reguljära mönster byggs upp.

Reguljära mönster kan innehålla flera symboler, metatecken, som har speciella betydelser. Metatecknen är . \ * [ ^ och $. Det enklaste av dem är punkten. Den matchar ett godtyckligt tecken. (Dock med undantag för nyrad-tecknet. Då grep och andra program som använder reguljära mönster endast betraktar en rad i taget, kan mönstren aldrig innehålla något nyrad-tecken.)$ grep 'n.ta' bellman
den skönsta nymf, som åt dig ler,
     inunder armen tag.
$
Mönstret n.ta matchade här ''nsta'' och ''n ta''. Om mönstret innehåller flera punkter så matchar varje punkt ett godtyckligt tecken; det behöver inte vara samma tecken varje gång:$ grep 'n..a' bellman
från Bacchi buller och tumult,
och du, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
     inunder armen tag.
$
Genast undrar man hur man ska kunna matcha en punkt. Svaret är att såväl punkten som de övriga metatecknen skyddas av det bakvända snedstrecket:$ grep 'tag\.' bellman
     inunder armen tag.
$
Om vi utelämnar skyddet för punkten, så matchar den bla blanktecken:$ grep 'tag.' bellman
     inunder armen tag.
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
$
Mycket ofta måste man skydda reguljära mönster eftersom de kan innehålla symboler som har en speciell betydelse för skalet. Tex måste mönstret tag\. skyddas för att skalet inte ska plocka bort det bakvända snedstrecket. Vi kommer därför konsekvent att använda apostrofer som beskydd för mönstret, även när det som i fallen n..a och tag. ovan inte är strängt nödvändigt. Om vi vill matcha en apostrof tvingas vi dock göra så här:$ grep \' bellman
tag dig se'n dito en, dito två, dito tre,
$

Reguljära mönster använder hakparenteser för att matcha en lista av tecken. Lyckligtvis är syntaxen densamma som för motsvarande jokertecken i skalet. Mönstret [A-J] matchar alltså en av versalerna från A till J.$ grep '[A-J]' bellman
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
$
Nästa uppgift är att finna de rader i filen bellman som innehåller någon stor bokstav. Detta är lätt, vi kan helt enkelt använda mönstret [A-ZÅÄÖ]. Men det finns ett bättre sätt att ange alla stora bokstäver, nämligen [:upper:]. (I tabell [*] ges en förteckning över de kategorier av tecken som kan anges på liknande sätt.)

 
Tabell: Kategorier som kan användas i listor.
 
Kategori av tecken Beteckning
Bokstäver [:alpha:]
Stora bokstäver [:upper:]
Små bokstäver [:lower:]
Siffror [:digit:]
Hexadecimala siffror [:xdigit:]
Alfanumeriska (alpha/digit) [:alnum:]
Blanktecken [:space:]
Skrivbara samt mellanslag [:print:]
Skrivbara [:graph:]
Skrivbara men ej alfanumeriska [:punct:]
Kontrolltecken [:cntrl:]

$ grep '[[:upper:]]' bellman
Så lunka vi så småningom
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
Tycker du, att graven är för djup,
$
En fördel med att skriva [:upper:] i stället för A-ZÅÄÖ är att avsikten med mönstret tydligare framgår. Än viktigare är att mönstret [:upper:] är oberoende av teckenuppsättning. Det matchar just de tecken som är stora bokstäver i användarens teckenuppsättning (förutsatt att lokalen LC_CTYPE eller LC_ALL är satt, se avsnitt 6.3).

Om man sätter tecknet ^ direkt efter den vänstra hakparentesen, så matchas ett godtyckligt tecken som inte räknas upp i listan. Så här finner vi de rader som innehåller texten ''du'' följt av något annat än kommatecken:$ grep 'du[^,]' bellman
och du, du yngling, lyd min lag:
     så dör du nöjdare.
$
Bara den första raden i filen bellman saknar såväl punkt som kommatecken:$ grep -v '[.,]' bellman
Så lunka vi så småningom
$

Den minsta beståndsdelen i reguljära mönster, som vi kan kalla för en ''atom'', matchar exakt ett tecken. Vi har redan beskrivit atomerna. Tabell [*] ger en sammanfattning av dem.

 
Tabell: Atomerna i reguljära mönster.
 
Atom Reguljärt mönster
Specifikt tecken t \ t om tecknet är något av
  . \ * [ ^ $, annars t
Godtyckligt tecken .
Tecken ur lista [ lista]
Tecken utanför lista [^ lista]
Understryknings- eller alfanumeriskt tecken \w
Motsatsen till \w \W

Men kanske är det fel att påstå att atomerna är den minsta beståndsdelen i reguljära mönster, för det finns ett antal olika sätt att matcha noll tecken - se tabell [*]. Metatecknen $ och ^ matchar början respektive slutet av en rad. Så här finner vi alltså de rader som inleds med ''och'':$ grep '^och' bellman lenngren
bellman:och du, du yngling, lyd min lag:
lenngren:och magen, kullrig som ett berg,
lenngren:och fann likören rätt begärlig.
lenngren:och ropte: Store Gud, vad är vårt usla liv?
$
Man brukar säga att tecknet ^ förankrar mönstret till början av en rad. Analogt förankrar dollartecknet ett mönster till slutet av en rad. Vilka rader slutar med tecknen ''an''?$ grep 'an$' bellman lenngren
lenngren:Vid sängen stod ett bord, där denne andans man
lenngren:Hans vördighet grep saken an
$
Vilka rader i bellman slutar med något annat än punkt eller kommatecken? $ grep '[^.,]$' bellman
Så lunka vi så småningom
och du, du yngling, lyd min lag:
$
I vilka rader är ''t'' det näst sista tecknet?$ grep t.$ bellman lenngren
bellman:från Bacchi buller och tumult,
bellman:     ditt timglas är nu fullt.
lenngren:med klunk för klunk och bit för bit,
$
Vilka rader i filen bellman inleds med stor bokstav?$ grep '^[[:upper:]]' bellman
Så lunka vi så småningom
Du gubbe, fäll din krycka ner,
Tycker du, att graven är för djup,
$

 
Tabell 10.3: Att matcha noll tecken.
 
Ankare Matchar noll tecken...
^ i början av en rad
$ i slutet av en rad
\< i början av ett ord
\> i slutet av ett ord
\b i kanten av ett ord
\B utom i kanten av ett ord

Tecknen \< matchar början av ett ord. Så här söker vi efter ord som börjar på ''dit'':$ grep '\<dit' bellman
     ditt timglas är nu fullt.
tag dig se'n dito en, dito två, dito tre,
$

Efter en atom kan man placera en ''multiplikator'', som upprepar atomen ett antal gånger. En förteckning av multiplikatorerna ges i tabell [*].

Metatecknet * betyder att föregående atom får upprepas hur många gånger som helst (inklusive noll).$ grep 'ul*t' bellman lenngren
bellman:från Bacchi buller och tumult,
bellman:     ditt timglas är nu fullt.
lenngren:matt utstäckt mellan tvenne lakan.
$
Mönstret ul*t matchade såväl ''ult'' som ''ullt'' och ''ut''.$ grep o.*st lenngren
Vår prost jag häromdagen såg
sig hävde upp mot isterhakan.
sin frukost redan färdig fann
$
Mönstret o.*st matchade här ''ost'' och ''ot ist''. Lägg märke till att .* matchar en godtycklig följd av tecken. Vilka av de rader som innehåller texten ''in'' slutar med ett kommatecken?$ grep 'in.*,$' bellman
Du gubbe, fäll din krycka ner,
$
Vilka ord börjar med d och slutar med n?$ grep '\<d[[:alpha:]]*n\>' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
den skönsta nymf, som åt dig ler,
$
De ord som gav träff ovan var ''döden'', ''din'' och ''den''.

Multiplikatorn \? upprepar föregående atom noll eller en gång:$ grep 'ul\?t' bellman lenngren
bellman:från Bacchi buller och tumult,
lenngren:matt utstäckt mellan tvenne lakan.
$
Multiplikatorn \+ upprepar föregående atom en eller fler gånger:$ grep 'ul\+t' bellman lenngren
bellman:från Bacchi buller och tumult,
bellman:     ditt timglas är nu fullt.
$

Nu ska vi leta efter en följd av små bokstäver som omges av ett ''n'' och ett ''e'':$ grep 'n[[:lower:]]*e' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
     inunder armen tag.
     så dör du nöjdare.
$

 
Tabell 10.4: Multiplikatorerna.
 
Multiplikator Matchar föregående atom...
* noll eller fler gånger
\? noll eller en gång
\+ en eller fler gånger
\{m\} exakt m gånger
\{m,\} minst m gånger
\{m,n\} mellan m och n gånger

Man kan mellan tecknen \{ och \} ange exakt hur många gånger atomen får upprepas. Texten ''nunde'' ur ordet ''inunder'' består av ett ''n'' följt av tre små bokstäver och ett ''e'':$ grep 'n[[:lower:]]\{3\}e' bellman
     inunder armen tag.
$
Härnäst tillåter vi upp till två små bokstäver mellan ''n'' och ''e'':$ grep 'n[[:lower:]]\{0,2\}e' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
     inunder armen tag.
$
Ovan fick vi träff på ''nne'', ''ne'' och ''nde''. Mönstret nedan tillåter 1-4 små bokstäver mellan ''n'' och ''e'':$ grep 'n[[:lower:]]\{1,4\}e' bellman
när döden ropar: Granne, kom,
     inunder armen tag.
$
Och så här upprepas atomen två eller fler gånger:$ grep 'n[[:lower:]]\{2,\}e' bellman
     inunder armen tag.
     så dör du nöjdare.
$


 
Tabell: Reguljära mönster.
 
Mönster Betyder
r1\|r2 Mönstret r1 eller mönstret r2
\(r\) Gör en atom av mönstret r,
  spara matchande text i ett register.
\n Innehållet i register n

Reguljära mönster kan skilja mellan olika alternativ. De alternativa mönstren separeras av tecknen \|. Det lodräta strecket \| betyder ''eller'', så det totala mönstret matchar de textsträngar som matchas av något av de alternativa mönstren. Så här finner vi de rader som innehåller något av orden ''du'', ''dig'' eller ''ditt'':$ grep 'du\|dig\|ditt' bellman
     ditt timglas är nu fullt.
och du, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
Tycker du, att graven är för djup,
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
     så dör du nöjdare.
$
Nu ska vi söka efter rader som innehåller ordet ''är'' efter något av orden ''du'', ''dig'' eller ''ditt''. Vi behöver då använda ''parenteserna'' \( och \).$ grep '\(du\|dig\|ditt\).*\<är\>' bellman
     ditt timglas är nu fullt.
Tycker du, att graven är för djup,
$

Ett reguljärt mönster som omges av tecknen \( och tecknen \) kan behandlas som en atom. Därigenom blir det möjligt att placera en multiplikator på mönstret.$ grep '\(du,\? \)\{2,\}' bellman
och du, du yngling, lyd min lag:
$

Den text som matchas av ett mönster som omges av \( och \), sparas i ett så kallat register. Man kan referera till texten i registret med tecknen \1. Så här finner vi de fall då a, b eller c förekommer två gånger i rad:$ grep '\([abc]\)\1' bellman
från Bacchi buller och tumult,
Du gubbe, fäll din krycka ner,
$
Ovan fick vi träff på ''cc'' i ordet ''Bacchi'' respektive ''bb'' i ordet ''gubbe''. Finns det några ord som slutar med en dubblerad bokstav?$ grep '\([[:alpha:]]\)\1\>' bellman
     ditt timglas är nu fullt.
Du gubbe, fäll din krycka ner,
Tycker du, att graven är för djup,
$
Ja, ''ditt'', ''fäll'' och ''att''.

Om det förekommer flera par av tecknen \( och \) i ett reguljärt mönster, så sparas den matchande texten i upp till nio olika register. Den text som matchar mönstret i parentesen längst till vänster sparas i register 1. Register 2 hör till parentesen näst längst till vänster osv. Innehållet i register n matchas av \n.


next up previous contents
Nästa: 10.2 Redigering i förbifarten Upp: 10. Textbehandling Förra: 10. Textbehandling
Goran Andersson
1999-03-08