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 >words
para 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 -o
solicitamos 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 uwords
matriz (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 tr
lí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}"
.