www.mamboteam.com
aptitude : me and my debian - a work in progress  
Startsida arrow bash arrow Textbehandling
2008-08-21
 
 
Huvudmeny
Startsida
debian
bash
Forum
Användarmeny
tidigare material
nyheter
grafik
Artikeltips
BadVista
Textbehandling  E-post

En sak som man bör lära sig om man håller på med Linux är regular expressions. Man behöver inte vara en speciellt avancerad användare för att ha nytta av den kunskapen.

 
$ echo "päppel äppel"
päppel äppel
 
$ echo "päppel äppel" | sed 's/\(.*\)\s\(.*\)/\2 \1/'
äppel päppel

Vad hände här? Strängen 'päppel äppel' leddes via en pipe '|' till till kommandot 'sed' som kastade om orden. Men det kastade ju inte särskillt mycket ljus över något, men nu vet du i alla fall vad en 'pipe' är... ett sätt att leda utdata från ett kommando så att det blir indata i ett annat.

Den RegExp som användes som parameter till sed-kommandot började med 's'... som i engelskans 'substitute' ('byt ut', fast en gång såg jag en film som hette 'The Substitute' och som var skitdålig. Där betydde det 'vikarien').
Det klarnar lite om man tittar på ett enklare exempel:

 
$ echo "Jag har alltid fel" | sed 's/fel/rätt/'
Jag har alltid rätt
 
$ echo "Jag har alltid fel, du har alltid rätt" | sed 's/fel/rätt/'
Jag har alltid rätt, du har alltid rätt
 
$ echo "Jag har alltid fel, du har alltid rätt" | \
    sed -e 's/rätt/fel/' -e 's/fel/rätt/'
Jag har alltid rätt, du har alltid fel

Det sista exemplet visar hur fler uttryck kan radas på varandra med växeln -e.

I RegExp syntax finns också en hel del specialtecken. \d som står för 'digit' och anger en siffra mellan 0-9, \w som står för 'word' och anger en bokstav a-z 0-9, \s som står för 'space' och anger tabb eller mellanslag. Vidare kan dessa utokas med '+' eller '*' där '+' kräver en eller flera förekomster medan '*' kräver noll eller flera. Tecknet '.' anger vilket tecken som helst utom radbrytning.
.*\s.* täcker alltså in allting fram till mellanslag(.*), mellanslag(\s), allting efter mellanslag(.*).

OK, men vad gör \( och \) där?
Genom att sätta ett uttryck inom parentes sparas det undan för att senare kunna hänvisas till. Det kallas backreference och är bra att kunna. Anledningen till att paranteserna föregås av backslash (\) beror på att det ska framgå att det är parentes som funktion och inte som tecken vi vill använda. Utan backslash skulle sed leta efter tecknet '(' och det är inte önskvärt här.
I den senare delen av uttrycket återkallas värdena: \2 \1. Innehållet som fångasts av den *andra* parentesen, ett mellanslag, innehållet som fångats av den *första* parentesen. Det är alltså anledningen till att orden kastades om.

Läs mer om regular expressions
 

Och nu över till något helt annat...


Denna text ska analyseras för ordfrekvens. Skiljetecken och annat som inte ska vara med i analysen raderas först. Listan ska sorteras i ordning så att det mest frekventa ordet kommer först.

Klistra in ovanstående text i en fil och döp den till 'test.txt'.
(Backslash \ i slutet av en rad anger att kommandot fortsätter på nästa rad)

 
$ sed 's/ /\n/g' test.txt | tr 'A-ZÅÄÖ' 'a-zåäö' | sort | \
  uniq -c | sort -nr
 
      3 ska
      3 i
      2 text
      2 och
      2 först.
      2 denna
      2 den
      1 vara
      1 till
      1 'test.txt'.

Ett sätt att byta ut tecken är 'tr'. Här byts versalerna A-Z,Å,Ä och Ö ut mot gemener. Kombinationen 'sort | uniq' kan kortas till 'sort -u', men inte när man vill använda växeln -c (count). Växlarna efter 'sort' -nr anger att indata ska sorteras numeriskt och i omvänd ordning (reversed order).

Skiljetecken måste avlägsnas. Både tr, sed och awk kan användas. Vi provar med sed.

$ sed "s/[.,:;-'\"\?\!]//g" test.txt

OK, det verkar få bort det mesta...

 
$ sed 's/ /\n/g' test.txt | sed "s/[.,:;-'\"\?\!]//g" | \
  tr 'A-ZÅÄÖ' 'a-zåäö' | 
    sort | uniq -c | sort -nr
 
      3 ska
      3 i
      2 text
      2 och
      2 först
      2 denna
      2 den
      1 vara
      1 till
      1 testtxt

Visserligen blev 'test.txt' till 'testtxt', men det får anses höra till vad vi kan tolerera. Well, om man vill ha bokstavsfrekvensen då?
Samma kommando med vissa modifieringar borde kunna användas. Skillnaden är att det inte är varje ord som ska stå på egen rad utan varje tecken.

 
$ sed 's/\(.\)/\1\n/g' test.txt
  D
  e
  n
  n
  a
  
  t
  e
  x
...
 
$ sed 's/\(.\)/\1\n/g' test.txt | tr 'A-ZÅÄÖ' 'a-zåäö' | \
  sort | uniq -c | sort -nr
 
     41
     24 e
     23 t
     23 a
     22 s
     21 n
     14 r
     11 k
     11 i
      8 o

Det går t.o.m. att få den procentuella förekomsten.

 
$ wc -c test.txt
264 test.txt
 
$ sed 's/\(.\)/\1\n/g' test.txt | tr 'A-ZÅÄÖ' 'a-zåäö' | \
  sort | uniq -c | sort -nr | 
    gawk '{printf "%.2f %s\n",100*($1/264),$2}'

Ett litet smolk i glädjebägaren är ju att man här själv måste ange hur många tecken orginalfilen innehåller. Borde inte det kunna skötas automatiskt?
Jo, 'getline' är svaret.

 
$ sed 's/\(.\)/\1\n/g' test.txt | tr 'A-ZÅÄÖ' 'a-zåäö' | \
  sort | uniq -c | sort -nr | \
    gawk '{"wc -c test.txt" | getline wc;printf "%.2f %s\n",\
  100*($1/wc),$2}'
    
    15,53
    9,09 e
    8,71 t
    8,71 a
    8,33 s
    7,95 n
    5,30 r
    4,17 k
    4,17 i
    3,03 o

Kommandot 'getline' fångar upp utdata från 'wc -c test.txt' (antalet tecken i filen) och lagrar det i variabeln wc. Variabeln används sedan för att räkna fram procentuell andel.
Med printf har man kontroll över hur data ska presenteras. Här används det för att sätta antalet decimaler till två.

Läs mer om frekvensanalys


sed och tr exempel
Klicka på bilden för att se video med exempel på hur 'sed' och 'tr' fungerar.

Kommentarer (0)Add Comment

Skriv kommentar

busy
 
< Föregående   Nästa >
 
Top! Top!