仕事
ここでパラメータはファイル名です!ファイルにテキストが含まれています。スクリプトの使命は、どの単語が最も頻繁に含まれるか(つまり)決定することです。
入出力例
(たとえば、テキストはボール、サッカー、バスケットボール、雪玉です。したがって、ボールは他の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 football
3に進みます。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}"
。