仕事

仕事

仕事

ここでパラメータはファイル名です!ファイルにテキストが含まれています。スクリプトの使命は、どの単語が最も頻繁に含まれるか(つまり)決定することです。


入出力例

(たとえば、テキストはボール、サッカー、バスケットボール、雪玉です。したがって、ボールは他の3つの世界の一部であるため、勝者になります。)


これまで私のコード

これまでこのコードを書いていますが、すべての出力に対して機能するわけではありません。

!/bin/sh
awk '{for(i=2;i<NF;i++) {s=$i; for(j=i+1;j<=NF;j++) print s=s FS $j}}' $1 | sort | uniq -c | sort -k1,1rn -k2 | sed 's/ *[^ ]* *//;q' | cut -f1 -d" "

答え1

words単語リストが1行に1単語しかないファイルにある場合(元のリストをtr ' ' '\n' <originalwords >words複数行に分割するために作成された可能性がある)、ループを実行します。

while IFS= read -r word; do
    grep -F -o -e "$word" words
done <words | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

単語リストの一部として最も頻繁に表示される単語を出力します(または、多くの単語が同じ回数で表示される場合は、リスト内のその単語が最初に表示される単語)。

これは、リスト自体をリストと一致させる一連のパターンとして使用します。-o一致する部分文字列を別の行に返す必要があります。

ループ単独の出力と質問に提供されているリストは次のとおりです。

play
ball
ball
ball
ball
football
basketball
snowball

次に、単語数を数えて最も頻繁に表示される単語を選択します。


一時ファイル処理を含む完全なスクリプト:

#!/bin/sh

tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"' EXIT      # delete temporary file upon exiting

tr -s ' ' '\n' <"${1:-/dev/stdin}" >"$tmpfile"  # convert into word list

while IFS= read -r word; do
    grep -F -o -e "$word" "$tmpfile"
done <"$tmpfile" | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

ファイルを指定しないと、スクリプトは標準入力からも読み取られます。

答え2

awk '{
        for (i=1; i<=NF; i++) {
                uwords[$i] = 0
                allwords[++idx] = $i
        }
     }
    END {
                if (idx == 0) exit
                max = 0
                for (w in uwords) {
                        count = 0
                        for (i=1; i<=idx; i++) {
                                if (allwords[i] ~ w) count++;
                        }
                        if (count > max) {
                                max = count
                                maxw = w
                        }
                }
                print maxw
        }'

入力をスキャンし、一意の単語リストとすべての単語リストを抽出します。 (固有の単語のリストは必要ないようですが、入力が大きいほど作業が効率的になることがあります)。 (したがってファイルにが含まれている場合はfootball football football3に進みます。ball)最も一致するものを追跡します。

uwords同点の場合(固有単語)、配列の最初の発生を報告します。これは必ずしもファイルに表示される最初の項目ではなく、アルファベット順の最初の項目でもありません。

単語に以下が含まれると、予期しない結果が生じる可能性があります。.*または[


Kusalanandaのshell + awkアプローチを好むが、極端な場合はエラーが必要ない場合は、次のようにします。

tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"' EXIT      # delete temporary file upon exiting

tr -s ' ' '\n' < "${1:-/dev/stdin}" > "$tmpfile"  # convert into word list

sort -u "$tmpfile" | while IFS= read -r word
do
    grep -F -o -e "$word" "$tmpfile"
done | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

単語リストを並べ替えると、一意の単語リストが得られるため、どの単語も複数回カウントされません。

このコードは、最大1つの入力ファイルがあると明示的に想定しています(ただし、ファイルが存在しない可能性があります。つまり、stdinで読むこと)。これは質問の表現と一致します。ただし、入力ファイルが複数ある場合(0、1、以上)、tr行を次に変更します。

cat -- "$@" | tr -s ' ' '\n' > "$tmpfile"         # convert into word list

UUOCと言えますが、

  • 複数の入力ファイルがある場合を処理します。
  • より読みやすいです< "${1:-/dev/stdin}"

関連情報