0
votes

Compter le nombre de mots différents dans un fichier txt dans Bash

Eh bien, je ne connais pas grand chose à la programmation chez bash, je suis nouveau dans ce domaine donc j'ai du mal à trouver un code pour itérer toutes les lignes d'un fichier txt, et compter combien de mots sont différents. Exemple: si un fichier txt contient "Nory était catholique parce que sa mère était catholique"
Le résultat doit donc être 7


0 commentaires

5 Réponses :


2
votes

Bien sûr. Je suppose que vous êtes d'accord pour définir les «mots» comme des choses séparées par un espace? Dans ce cas, essayez quelque chose comme ceci:

tr -s " " "\n" < filename | sort -u | wc -l

Cette commande dit:

  • Vider le contenu du nom de fichier

  • Remplacez plusieurs espaces par un seul espace

  • Remplacez les espaces par une nouvelle ligne

  • Trier et "unifier" la liste

  • Imprimer le nombre de lignes

Selon le commentaire, vous pouvez techniquement vous en sortir sans utiliser cat si vous le souhaitez, avec ce qui suit:

sed -r -e "s/[ ]+/ /g" -e "s/ /\n/g" filename | sort -u | wc -l

De plus, à partir d'un autre commentaire, vous pouvez éventuellement utiliser tr (surtout avec son indicateur -s pour gérer les espaces répétés) au lieu de sed avec quelque chose comme:

cat filename | sed -r -e "s/[ ]+/ /g" -e "s/ /\n/g" | sort -u | wc -l

La morale de l'histoire est qu'il y a plusieurs façons d'accomplir ce genre de chose, sans parler des autres réponses complètes qui sont données ici :-) Ma réponse préférée à ce stade est celle d'Ed Morton que j'ai votée pour en conséquence.


6 commentaires

Félicitations, vous remportez le prix "Utilisation inutile de chat" d'aujourd'hui :-) Essayez sed -r -e "s / [] + / / g" -e "s / / \ n / g" nom de fichier | trier ... à la place.


Ha. Assez juste: p


S'ok, ça marche même avec ce truc mérite donc un vote positif.


sed -r -e "s / [] + / / g" -e "s / / \ n / g" est identique à tr -s '' '\ n' < / code>


J'ai supprimé le wc -l pour voir comment cela fonctionne et j'ai découvert que cela fonctionne mais certains mots égaux n'ont pas été supprimés car ils sont séparés par des tabulations, c'était comme ceci Ex: mot mot mot


correct. Si vous utilisez la solution d'Ed Morton, elle gérera tous les séparateurs d'espaces blancs. Celui-ci gère simplement "" la séparation.



-1
votes
cat yourfile.txt | xargs -n1 | sort | uniq -c > youroutputfile.txt
xargs -n1 = put one word per linesort = sortsuniq -c = counts occurrences of distinct valuessource

6 commentaires

Utiliser xargs fonctionnerait bizarrement. Par exemple, quote: "this is a quote" compterait 2 mots. xargs analyse les citations.


oh bizarre, pourquoi ne compterait-il que deux?


Vous manquez un cat au début de cette commande? De plus, cela ne donne-t-il pas à chaque mot sa quantité individuelle plutôt que la quantité totale?


deuxième m'a deviné après avoir vu l'autre réponse et l'ai enlevée


xargs (par défaut) prend en charge les guillemets, il analyse l'entrée entre guillemets comme un argument. Donc echo '123 "c'est entre guillemets"' | xargs -n1 affichera deux lignes.


@TravisG: Un autre problème avec xargs , en plus des guillemets, est que la ponctuation fait partie des mots. Si l'entrée contient quelque chose comme A + B, C (sans espaces), il s'agit d'un seul mot d'entrée pour xargs, pas trois. Une solution consisterait à diriger l’entrée d’abord via tr et à remplacer tout ce qui n’est pas une lettre par un espace, et puis l’alimenter à xargs .



0
votes

Je le ferais comme ça, avec des commentaires:

echo "Nory was a Catholic because her mother was a Catholic" |
# tr replace
# -s - squeeze
# -c - complementary
# [a-zA-Z0-9_] - all letters, number and underscore
# but complementary set, so all non letters, not numbers and not underscores.
# replace them by newline
tr -sc '[a-zA-Z0-9_]' '\n' |
# and sort unique and display count
sort -u | wc -l

Testé sur repl bash .

A décidé d'utiliser [a-zA-Z0-9_] , car c'est ainsi que GNU sed \ w extension correspond à un mot.


3 commentaires

Pourquoi avez-vous besoin de sed là-bas? tr peut presser des séries de non-lettres avant de les remplacer


Pour supprimer les lignes vides. Ex. Bonjour, je m'appelle kamil. entraînera une ligne vide de , remplacée par deux \ n \ n .


echo Bonjour, je m'appelle kamil. | tr -cs [: alpha:] '\ n' ne génère pas de lignes vides.



4
votes
$ grep -o '[^[:space:]]*' file | sort -u | wc -l
7

3 commentaires

Salut @Ed Morton, j'aime la réponse (je l'ai votée pour) mais je pense que ce serait mieux avec un + de dire "un ou plusieurs non espaces" plutôt que le * qui dit "zéro ou plus" ... Il est possible que votre réponse gère cela en raison de l'indicateur -o (je ne suis pas sur un shell à tester) mais je pense que ce serait plus sémantiquement correct si rien d'autre si édité.


Si j'ai utilisé + au lieu de * , alors je devrais ajouter -E pour prendre en charge les ERE ou apporter d'autres modifications, je pense que * est très bien.


Ok alors, assez bien



1
votes

Vous pouvez également mettre le texte en minuscules afin que les mots se comparent indépendamment de la casse.

Filtrez également les mots avec la classe de caractères [: alnum:] , plutôt que [a-zA-Z0 -9_] qui n'est valide que pour US-ASCII, et échouera dramatiquement avec le grec ou le turc.

#!/usr/bin/env bash
echo "The uniq words are the words that appears at least once, regardless of casing." |
  # Turn text to lowercase
  tr '[:upper:]' '[:lower:]' |
  # Split alphanumeric with newlines
  tr -sc '[:alnum:]' '\n' |
  # Sort uniq words
  sort -u |
  # Count lines of unique words
  wc -l


0 commentaires