Tarefa

Tarefa

Tarefa

O parâmetro aqui é um nome de arquivo! O arquivo contém um texto. A tarefa do script é decidir qual palavra está contida com mais frequência em outras palavras.


Exemplo de entrada e saída

(por exemplo, o texto é: jogar bola futebol basquete bola de neve - portanto a bola é a vencedora porque faz parte de outros três mundos).


Meu código até agora

Eu fiz esse código até agora, mas não funciona para todas as saídas

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

Responder1

Se a lista de palavras estiver em um arquivo chamado words, com uma única palavra em cada linha (possivelmente criada para tr ' ' '\n' <originalwords >wordsdividir a lista original em múltiplas linhas), então o loop

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

gerará a palavra que ocorre na maioria das vezes como parte das palavras da lista (ou, se muitas palavras ocorrerem igualmente muitas vezes, aquela que ocorreu primeiro na lista).

Isso é feito usando a própria lista como um conjunto de padrões para combinar com a lista. Com -opedimos que as substrings correspondentes sejam retornadas em linhas individuais.

A saída do loop sozinha, com a lista dada na questão será

play
ball
ball
ball
ball
football
basketball
snowball

Basta então contar essas palavras e destacar aquela que ocorre com mais frequência.


Como um script completo, com manipulação de arquivos temporários:

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

O script lê adicionalmente a entrada padrão se não houver nenhum arquivo especificado.

Responder2

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

Digitalize a entrada e extraia uma lista de palavras exclusivas e uma lista de todas as palavras. (Acho que não precisamos da lista de palavras únicas, mas isso pode tornar as coisas mais eficientes no caso de uma entrada grande.) Então, para cada palavra única, conte quantas palavras no arquivo correspondem a ela. (Portanto, se o arquivo contiver football football football, isso contará 3 para ball.) Acompanhe aquele com mais correspondências.

Em caso de empate, informa a palavra que aparece primeiro no uwordsarray (palavras únicas). Este não é necessariamente o primeiro que aparece no arquivo, nem é o primeiro em ordem alfabética.

Isto pode produzir resultados inesperados se alguma das palavras contiver., *ou [.


Se você preferir a abordagem shell + awk de Kusalananda, mas não deseja o erro extremo, faça o seguinte:

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

Ao classificar a lista de palavras, obtemos uma lista de palavras únicas e, portanto, não contamos nenhuma palavra várias vezes.

Observe que este código assume explicitamente que existe no máximo um arquivo de entrada (mas não pode haver nenhum arquivo; ou seja, lido do stdin). Isso é consistente com a formulação da pergunta. No entanto, se puder haver qualquer número de arquivos de entrada (zero, um,ou mais), altere a trlinha para

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

Provavelmente é um UUOC, mas

  • ele lida com o caso de dois ou mais arquivos de entrada, e
  • é mais legível do que < "${1:-/dev/stdin}".

informação relacionada