GNU/Linux >> Linux の 問題 >  >> Linux

awkを使用して文字の頻度を計算します

私は最近、文字のタイルを使用して単語を作成するゲームを書き始めました。ゲームを作成するには、英語の通常の単語全体の文字の頻度を知る必要がありました。これにより、便利な文字タイルのセットを提示できました。文字の頻度はウィキペディアを含むさまざまな場所で議論されていますが、私は文字の頻度を自分で計算したかったのです。

Linuxは、/usr/share/dict/words内の単語のリストを提供します ファイルなので、使用する可能性のある単語のリストがすでにあります。 words ファイルには、必要な単語がたくさん含まれていますが、含まれていない単語もいくつかあります。複合語(ハイフンやスペースなし)または適切な名詞(大文字なし)ではないすべての単語のリストが必要でした。そのリストを取得するには、grepを実行します 小文字のみで構成される行のみを引き出すコマンド:

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

この正規表現はgrepに要求します 小文字のみのパターンに一致します。文字^ および$ パターン内は、それぞれ行の開始と終了を表します。 [a-z] グループ化は小文字のaのみに一致します zへ 。

出力の簡単なサンプルは次のとおりです。

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

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事

そして、はい、それらはすべて有効な言葉です。たとえば、「aahed」は、リラクゼーションの場合のように、「aah」の過去形の感嘆符です。そして「aalii」はふさふさした熱帯低木です。

ここで、gawkを作成する必要があります。 各単語の文字を数える作業を実行し、見つかった各文字の相対頻度を出力するスクリプト。

文字を数える

gawkの文字を数える1つの方法 各入力行の各文字を繰り返し処理し、各文字の出現回数をカウントすることです a zへ 。 substr 関数は、より大きな文字列から、1文字など、指定された長さの部分文字列を返します。たとえば、このコード例では、各文字cを評価します。 入力から:

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

グローバル文字列LETTERSで開始する場合 アルファベットが含まれているので、indexを使用できます アルファベットの1文字の位置を見つける関数。 gawkを展開します 文字のみを評価するコード例a zへ 入力:

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

index関数は、LETTERSから最初に出現する文字を返すことに注意してください。 文字列。最初の文字が1で始まり、見つからない場合は0で始まります。 26要素の長さの配列がある場合は、その配列を使用して各文字の出現回数を数えることができます。これをコード例に追加してインクリメントします(++を使用) )入力に表示される各文字の数:

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];
        }
    }
}

相対度数の印刷

gawkの後 スクリプトはすべての文字をカウントします。見つかった各文字の頻度を印刷したいと思います。入力からの各文字の総数ではなく、相対頻度に関心があります。 各文字の。相対度数は、出現回数が最も少ない文字( q の文字など)になるようにカウントをスケーリングします。 )は1に設定され、他の文字はそれに関連しています。

文字aのカウントから始めましょう 、次にその値を他の各文字のカウントと比較します b zへ :

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

そのループの終わりに、変数min 任意の文字の最小数が含まれます。これを使用して、各文字の相対度数を印刷するためのカウントのスケールを提供できます。たとえば、出現回数が最も少ない文字が qの場合 、次にmin qと等しくなります カウント。

次に、各文字をループして、相対的な頻度で印刷します。各カウントをminで割ります 相対度数を印刷します。つまり、最小カウントの文字は相対度数1で印刷されます。別の文字が最小カウントの2倍の頻度で表示される場合、その文字の相対度数は2になります。私だけですここで整数値に関心があるので、2.1と2.9は私の目的では2と同じです:

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);
    }
}

すべてをまとめる

今、私はgawkを持っています 入力内の文字の相対頻度をカウントできるスクリプト:

#!/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);
    }
}

これをletter-freq.awk コマンドラインから簡単に使用できるようにします。

必要に応じて、chmod +xを使用することもできます ファイルを独自に実行可能にします。 #!/usr/bin/gawk -f 最初の行は、Linuxが/usr/bin/gawkを使用してスクリプトとして実行することを意味します プログラム。そして、gawk コマンドラインは-fを使用します スクリプトとして使用するファイルを指定するには、-fをぶら下げる必要があります。 letter-freq.awkを実行するようにします シェルでは、/usr/bin/gawk -f letter-freq.awkを実行していると適切に解釈されます。 代わりに。

いくつかの簡単な入力でスクリプトをテストできます。たとえば、アルファベットをgawkにフィードした場合 スクリプトでは、各文字の相対頻度は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

その例を繰り返しますが、文字 eのインスタンスを追加します 文字eを印刷します 相対度数が2で、1文字おきに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

そして今、私は大きな一歩を踏み出すことができます! grepを使用します /usr/share/dict/wordsを使用したコマンド ファイルを作成し、すべて小文字で綴られたすべての単語の文字頻度を特定します:

$ 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

/usr/share/dict/words内のすべての小文字の単語 ファイル、文字 j q 、および x 最も頻度が低い。文字z また、かなりまれです。当然のことながら、文字 e 最も頻繁に使用されます。


Linux
  1. Linuxでcronを使用する方法

  2. Awkおよび正規表現を使用してファイル内のテキストまたは文字列をフィルタリングする方法

  3. LinuxでSuコマンドを使用する方法

  1. Nginxを使用してリダイレクトする方法

  2. gawkの初心者向けガイド

  3. Awkの外部変数?

  1. Awkを使用して5列を含む行のみを印刷するにはどうすればよいですか?

  2. SED を使用した単語の最初の文字の大文字化

  3. grep と awk の使用