タスク

タスク

タスク

ここでのパラメータはファイル名です。ファイルにはテキストが含まれています。スクリプトのタスクは、他の単語にどの単語が最も頻繁に含まれるかを判断することです。


入力と出力の例

(例: プレー ボール フットボール バスケットボール スノーボール - したがって、ボールは他の 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つの単語が含まれている場合(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 }'

リスト内の単語の中で最も多く出現する単語を出力します (または、多くの単語が同じ回数出現する場合は、リスト内で最初に出現した単語の 1 つを出力します)。

これは、リスト自体をリストと照合するパターンのセットとして使用することで行われます。 では、-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ですが、

  • 2つ以上の入力ファイルがある場合も処理し、
  • よりも読みやすいです< "${1:-/dev/stdin}"

関連情報