Aufgabe

Aufgabe

Aufgabe

Der Parameter ist hier ein Dateiname! Die Datei enthält einen Text. Die Aufgabe des Skripts ist es zu entscheiden, welches Wort am häufigsten in anderen Wörtern vorkommt.


Beispiele für Eingabe und Ausgabe

(Beispiel: Der Text lautet: Ball spielen, Fußball, Basketball, Schneeball – deshalb ist der Ball der Gewinner, weil er zu drei anderen Welten gehört).


Mein Code bisher

Ich habe diesen Code bisher gemacht, aber er funktioniert nicht für jede Ausgabe

!/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" "

Antwort1

Wenn sich die Liste der Wörter in einer Datei namens befindet wordsund jede Zeile ein einzelnes Wort enthält (möglicherweise erstellt mit , tr ' ' '\n' <originalwords >wordsum die ursprüngliche Liste in mehrere Zeilen aufzuteilen), dann wird die Schleife

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 }'

gibt das Wort aus, das in der Liste am häufigsten vorkommt (oder, wenn viele Wörter gleich oft vorkommen, dasjenige der Wörter, das in der Liste zuerst vorkam).

Dies geschieht, indem die Liste selbst als Mustersatz verwendet wird, der mit der Liste abgeglichen wird. Mit -ofordern wir die Rückgabe übereinstimmender Teilzeichenfolgen in einzelnen Zeilen an.

Die Ausgabe der Schleife allein mit der in der Frage angegebenen Liste lautet

play
ball
ball
ball
ball
football
basketball
snowball

Dann müssen Sie diese Wörter nur noch zählen und dasjenige heraussuchen, das am häufigsten vorkommt.


Als vollständiges Skript mit temporärer Dateiverwaltung:

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

Das Skript liest zusätzlich von der Standardeingabe, wenn keine Datei angegeben ist.

Antwort2

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
        }'

Scannen Sie die Eingabe und extrahieren Sie eine Liste eindeutiger Wörter und eine Liste aller Wörter. (Ich vermute, wir brauchen die Liste eindeutiger Wörter nicht, aber bei einer großen Eingabe könnte sie die Arbeit effizienter machen.) Zählen Sie dann für jedes eindeutige Wort, wie viele Wörter in der Datei damit übereinstimmen. (Wenn die Datei also enthält football football football, zählt das 3 für ball.) Behalten Sie das Wort mit den meisten Übereinstimmungen im Auge.

Bei einem Gleichstand wird das Wort gemeldet, das als erstes im uwordsArray (eindeutige Wörter) erscheint. Dies ist nicht notwendigerweise das erste Wort, das in der Datei erscheint, und auch nicht das alphabetisch erste.

Dies kann zu unerwarteten Ergebnissen führen, wenn eines der Wörter., *oder [.


Wenn Sie den Shell+Awk-Ansatz von Kusalananda bevorzugen, aber den Grenzfallfehler vermeiden möchten, gehen Sie wie folgt vor:

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 }'

Durch das Sortieren der Wortliste erhalten wir eine Liste mit eindeutigen Wörtern und zählen somit keine Wörter mehrfach.

Beachten Sie, dass dieser Code explizit davon ausgeht, dass höchstens eine Eingabedatei vorhanden ist (es könnte aber auch keine Datei vorhanden sein, d. h., es wird von stdin gelesen). Dies entspricht der Formulierung der Frage. Wenn es jedoch eine beliebige Anzahl von Eingabedateien geben kann (null, eins,oder mehr), ändern Sie die trZeile in

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

Man könnte argumentieren, dass es sich um ein UUOC handelt, aber

  • Es behandelt den Fall von zwei oder mehr Eingabedateien und
  • es ist besser lesbar als < "${1:-/dev/stdin}".

verwandte Informationen