Tarea

Tarea

Tarea

¡El parámetro aquí es un nombre de archivo! El archivo contiene un texto. La tarea del guión es decidir qué palabra se contiene con mayor frecuencia en otras palabras.


Ejemplo de entrada y salida

(por ejemplo, el texto es: jugar a la pelota, fútbol, ​​baloncesto, bola de nieve; por lo tanto, la pelota gana porque forma parte de otros tres mundos).


Mi código hasta ahora

Hice este código hasta ahora, pero no funciona para todos los resultados.

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

Respuesta1

Si la lista de palabras está en un archivo llamado words, con una sola palabra en cada línea (posiblemente creada con tr ' ' '\n' <originalwords >wordspara dividir la lista original en varias líneas), entonces el bucle

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

generará la palabra que aparece más veces como parte de las palabras de la lista (o, si muchas palabras aparecen la misma cantidad de veces, la de esas palabras que apareció primero en la lista).

Para ello, utiliza la lista misma como un conjunto de patrones para compararlos con la lista. Con -osolicitamos que se devuelvan subcadenas coincidentes en líneas individuales.

La salida del bucle sola, con la lista dada en la pregunta será

play
ball
ball
ball
ball
football
basketball
snowball

Entonces sólo es cuestión de contar esas palabras y seleccionar la que aparece con más frecuencia.


Como script completo, con manejo de archivos temporales:

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

El script además lee desde la entrada estándar si no se especifica ningún archivo.

Respuesta2

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

Escanee la entrada y extraiga una lista de palabras únicas y una lista de todas las palabras. (Supongo que no necesitamos la lista de palabras únicas, pero puede hacer que las cosas sean más eficientes en el caso de una entrada grande). Luego, para cada palabra única, cuente cuántas palabras en el archivo coinciden con ella. (Entonces, si el archivo contiene football football football, eso cuenta 3 para ball). Mantenga un registro del que tenga más coincidencias.

En caso de empate, informa la palabra que aparece primero en la uwordsmatriz (palabras únicas). Este no es necesariamente el primero que aparece en el archivo, ni tampoco el primero alfabéticamente.

Esto puede producir resultados inesperados si alguna de las palabras contiene., *o [.


Si prefiere el enfoque shell+awk de Kusalananda, pero no quiere el error de caso límite, haga esto:

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

Al ordenar la lista de palabras, obtenemos una lista de palabras únicas y, por lo tanto, no contamos ninguna palabra varias veces.

Tenga en cuenta que este código asume explícitamente que hay como máximo un archivo de entrada (pero no podría haber ningún archivo; es decir, leído desde la entrada estándar). Esto es consistente con la formulación de la pregunta. Sin embargo, si puede haber cualquier número de archivos de entrada (cero, uno,o más), cambie la trlínea a

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

Podría decirse que es un UUOC, pero

  • maneja el caso de dos o más archivos de entrada, y
  • es más legible que < "${1:-/dev/stdin}".

información relacionada