Štatistika znakov

V tomto prípade bolo potrebné vytvoriť skript, ktorý bude počítať výskyt ASCII znakov (anglická abeceda). Nerozlišujú sa malé a veľké písmenká. Každému písmenku je priradený ASCII kód, čo s výhodou využijeme pri konštrukcii histogramu výskytu.

Skript som sa rozhodla riešiť tak, že zadaný názov súboru sa mu bude vkladať ako parameter a ten následne spracuje. Na začiatku teda prebehne kontrola, či je daný parameter prítomný a potom nasleduje kontrola, či daný súbor aj skutočne existuje.

if [[ !$# -ge "1" ]]; then

Pripravíme si prázdny histogram, využijeme dátovú štruktúru pole o 25 prvkoch. Tento počet zodpovedá počtu písmen anglickej abecedy.

for i in {0..25}; do
  histogram[$i]=0
done

Chceme pracovať s jednotlivými písmenkami súboru, využijeme cyklu for, pričom budeme prechádzať jednotlivé položky zoznamu, ktorý budú tvoriť práve písmenká. Písmená je však nutné zo zdrojového súboru najprv získať, jednotlivé kroky spracovania budú tvorené postupnosťou príkazov:

cat $1 | sed 's/[^a-zA-Z]//g' |

Najprv celý obsah vstupného súboru vypíšeme (keďže bol zadaný ako parameter pri spustení skriptu, dostaneme sa k nemu pomocou premennej $1). Obsah súboru potom preženieme editorom sed (stream editor), ktorý pomocou uvedeného príkazu (s znamená "substitute" a g znamená globálne - v celom vstupnom súbore) odstráni všetky znaky, ktoré NEzodpovedajú zadanému rozsahu, t.j. ponechá iba písmenká anglickej abecedy.

tr [:upper:] [:lower:] | sed 's/[\r]//g'

Budeme pracovať iba s malými písmenkami, veľké prevedieme na malé pomocou nástroja tr (translate). Výstup pošleme zase editoru sed, kde ešte pre istotu odstránime znaky "carriage return", ktoré sa môžu z nejakých dôvodov v texte vyskytnúť (nepodarilo sa mi odhaliť príčinu).

V poslednom kroku jednotlivé malé písmenká prevedieme na ich číselnú reprezentáciu ASCII kódom (desiatkovo). Tento krok je netriviálny, riešenie nie je priamočiare, preto som si pomohla radami na internete a použila program od s nasledovnými parametrami, ktoré potrebnú konverziu zabezpečia. Čísla znakov budú využité ako indexy do histogramu!

od -An -t dC

Teraz už nič nebráni cyklu for prechádzať zoznam, v tomto prípade jednotlivých čísel (ASCII hodnôt znakov) a upravovať histogram:

if [[ $i -ge 97 && $i -le 122 ]]; then 
  let histogram[$(($i-97))]++

Získané hodnoty použijeme priamo ako indexy do poľa, kde na príslušnom indexe si udržujeme počet výskytov jednotlivých znakov (a..z). Pri indexácii musíme načítanú hodnotu znížiť o 97. Táto hodnota je desiatkový ASCII kód pre písmenko 'a'. Zakaždým hodnotu na príslušnom indexe zvýšime o 1.

V poslednom kroku už len vhodne histogram vypíšeme:

printf "%d \n" "${histogram[@]}" | nl -v 97

Vypíšeme hodnoty celého poľa, na každý riadok jednu - tie reprezentujú počet výskytov znaku. Následne si jednotlivé riadky očíslujeme, počnúc hodnotou 97.

awk '{printf "%c %d\n", $1, $2}' | sort -k2nr

A ako posledný krok spravíme menší trik - editorom awk si vypíšeme znovu obsah jednotlivých stĺpcov na riadku (pomocou premenných $1, $2 - máme iba dva stĺpce textu), pričom prvý stĺpec si vypíšeme ako ASCII znak - a to na základe jeho hodnoty, ktorá sa tam už nachádza. Nakoniec si ešte výstup zoradíme (podľa hodnôt v druhom stĺpci) od najväčšieho počtu výskytu k najmenšiemu.