GNU/Linux >> Belajar Linux >  >> Linux

Gunakan awk untuk menghitung frekuensi huruf

Saya baru-baru ini mulai menulis permainan di mana Anda membangun kata-kata menggunakan ubin huruf. Untuk membuat game, saya perlu mengetahui frekuensi huruf di seluruh kata biasa dalam bahasa Inggris, jadi saya bisa menyajikan satu set ubin huruf yang berguna. Frekuensi huruf dibahas di berbagai tempat, termasuk di Wikipedia, tetapi saya ingin menghitung sendiri frekuensi hurufnya.

Linux menyediakan daftar kata di /usr/share/dict/words file, jadi saya sudah memiliki daftar kemungkinan kata-kata untuk digunakan. words file berisi banyak kata yang saya inginkan, tetapi beberapa yang tidak saya inginkan. Saya ingin daftar semua kata yang bukan kata majemuk (tanpa tanda hubung atau spasi) atau kata benda (tanpa huruf besar). Untuk mendapatkan daftar itu, saya dapat menjalankan grep perintah untuk menarik hanya baris yang hanya terdiri dari huruf kecil:

$ grep  '^[a-z]*$' /usr/share/dict/words

Ekspresi reguler ini menanyakan grep untuk mencocokkan pola yang hanya huruf kecil. Karakter ^ dan $ dalam pola masing-masing mewakili awal dan akhir baris. [a-z] pengelompokan hanya akan cocok dengan huruf kecil a ke z .

Berikut ini contoh cepat output:

$ grep  '^[a-z]*$' /usr/share/dict/words | head
a
aa
aaa
aah
aahed
aahing
aahs
aal
aalii
aaliis

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Dan ya, itu semua adalah kata-kata yang valid. Misalnya, "aahed" adalah bentuk lampau dari seruan "aah", seperti dalam relaksasi. Dan "aalii" adalah semak tropis lebat.

Sekarang saya hanya perlu menulis gawk skrip untuk melakukan pekerjaan menghitung huruf dalam setiap kata, dan kemudian mencetak frekuensi relatif dari setiap huruf yang ditemukan.

Menghitung huruf

Salah satu cara menghitung huruf di gawk adalah untuk mengulangi setiap karakter di setiap baris input dan menghitung kemunculan setiap huruf a ke z . substr function akan mengembalikan substring dengan panjang tertentu, seperti satu huruf, dari string yang lebih besar. Misalnya, contoh kode ini akan mengevaluasi setiap karakter c dari masukan:

{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
    }
}

Jika saya mulai dengan string global LETTERS yang berisi alfabet, saya dapat menggunakan index berfungsi untuk mencari letak satu huruf dalam alfabet. Saya akan memperluas gawk contoh kode untuk mengevaluasi hanya huruf a ke z di masukan:

BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
 
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
    }
}

Perhatikan bahwa fungsi indeks mengembalikan kemunculan huruf pertama dari LETTERS string, dimulai dengan 1 pada huruf pertama, atau nol jika tidak ditemukan. Jika saya memiliki array yang panjangnya 26 elemen, saya dapat menggunakan array untuk menghitung kemunculan setiap huruf. Saya akan menambahkan ini ke contoh kode saya untuk menambah (menggunakan ++ ) hitungan untuk setiap huruf seperti yang muncul di input:

BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
 
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
 
        if (ltr > 0) {
            ++count[ltr];
        }
    }
}

Frekuensi relatif pencetakan

Setelah gawk skrip menghitung semua huruf, saya ingin mencetak frekuensi setiap huruf yang ditemukan. Saya tidak tertarik pada jumlah total setiap huruf dari input, melainkan frekuensi relatif dari setiap huruf. Frekuensi relatif menskalakan jumlah sehingga huruf dengan kemunculan paling sedikit (seperti huruf q ) disetel ke 1, dan huruf lainnya relatif terhadap itu.

Saya akan mulai dengan menghitung huruf a , lalu bandingkan nilai tersebut dengan jumlah untuk setiap huruf lainnya b ke z :

END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
}

Di akhir perulangan itu, variabel min berisi jumlah minimum untuk setiap huruf. Saya dapat menggunakannya untuk memberikan skala hitungan untuk mencetak frekuensi relatif setiap huruf. Misalnya, jika huruf dengan kemunculan terendah adalah q , lalu min akan sama dengan q hitung.

Kemudian saya mengulang setiap huruf dan mencetaknya dengan frekuensi relatifnya. Saya membagi setiap hitungan dengan min untuk mencetak frekuensi relatif, yang berarti huruf dengan hitungan terendah akan dicetak dengan frekuensi relatif 1. Jika huruf lain muncul dua kali lebih sering dari hitungan terendah, huruf tersebut akan memiliki frekuensi relatif 2. I'm only tertarik dengan nilai integer di sini, jadi 2.1 dan 2.9 sama dengan 2 untuk tujuan saya:

END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
 
    for (ltr = 1; ltr <= 26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

Menggabungkan semuanya

Sekarang saya punya gawk skrip yang dapat menghitung frekuensi relatif huruf dalam inputnya:

#!/usr/bin/gawk -f
 
# only count a-z, ignore A-Z and any other characters
 
BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
 
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
 
        if (ltr > 0) {
            ++count[ltr];
        }
    }
}
 
# print relative frequency of each letter
   
END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
 
    for (ltr = 1; ltr <= 26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

Saya akan menyimpannya ke file bernama letter-freq.awk sehingga saya dapat menggunakannya dengan lebih mudah dari baris perintah.

Jika mau, Anda juga dapat menggunakan chmod +x untuk membuat file dapat dieksekusi sendiri. #!/usr/bin/gawk -f pada baris pertama berarti Linux akan menjalankannya sebagai skrip menggunakan /usr/bin/gawk program. Dan karena gawk baris perintah menggunakan -f untuk menunjukkan file mana yang harus digunakan sebagai skrip, Anda memerlukan -f yang menggantung itu sehingga mengeksekusi letter-freq.awk di shell akan ditafsirkan dengan benar sebagai menjalankan /usr/bin/gawk -f letter-freq.awk sebagai gantinya.

Saya dapat menguji skrip dengan beberapa input sederhana. Misalnya, jika saya memasukkan alfabet ke dalam gawk . saya skrip, setiap huruf harus memiliki frekuensi relatif 1:

$ echo abcdefghijklmnopqrstuvwxyz | gawk -f letter-freq.awk
a 1
b 1
c 1
d 1
e 1
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

Mengulangi contoh itu tetapi menambahkan contoh tambahan dari huruf e akan mencetak huruf e dengan frekuensi relatif 2 dan setiap huruf lainnya sebagai 1:

$ echo abcdeefghijklmnopqrstuvwxyz | gawk -f letter-freq.awk
a 1
b 1
c 1
d 1
e 2
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

Dan sekarang saya dapat mengambil langkah besar! Saya akan menggunakan grep perintah dengan /usr/share/dict/words arsipkan dan identifikasi frekuensi huruf untuk semua kata yang dieja seluruhnya dengan huruf kecil:

$ grep  '^[a-z]*$' /usr/share/dict/words | gawk -f letter-freq.awk
a 53
b 12
c 28
d 21
e 72
f 7
g 15
h 17
i 58
j 1
k 5
l 36
m 19
n 47
o 47
p 21
q 1
r 46
s 48
t 44
u 25
v 6
w 4
x 1
y 13
z 2

Dari semua kata kecil di /usr/share/dict/words file, huruf j , q , dan x paling jarang terjadi. Huruf z juga cukup langka. Tidak mengherankan, huruf e adalah yang paling sering digunakan.


Linux
  1. Cara Menggunakan Awk dan Ekspresi Reguler untuk Memfilter Teks atau String dalam File

  2. Cara Menggunakan Nginx untuk Mengarahkan

  3. Panduan pemula untuk melongo

  1. Cara menggunakan BusyBox di Linux

  2. Bagaimana saya menggunakan cron di Linux

  3. Huruf Besar Kata Pertama Menggunakan SED

  1. Cara menggunakan Perintah Su di Linux

  2. Variabel Eksternal Dalam Awk?

  3. Bagaimana Cara Menggunakan Awk Untuk Mencetak Hanya Garis yang Berisi 5 Kolom?