Je me demandais comment compter le nombre d'un caractère spécifique dans chaque ligne avec certains utilitaires de traitement de texte?
Par exemple, compter "
dans chaque ligne du texte suivant
"hello!"
Thank you!
La première ligne a deux et la deuxième ligne a 0.
Un autre exemple consiste à compter (
dans chaque ligne.
Réponses:
Vous pouvez le faire avec
sed
etawk
:Où se
dat
trouve votre exemple de texte, sed supprime (pour chaque ligne) tous les"
caractères autres que des caractères etawk
affiche pour chaque ligne sa taille (c’estlength
-à- dire qu’elle correspond àlength($0)
, où$0
indique la ligne en cours).Pour un autre personnage, il vous suffit de changer l'expression sed. Par exemple pour
(
:Mise à jour:
sed
est un peu excessif pour la tâche -tr
suffit. Une solution équivalente avectr
est:Ce qui
tr
supprime tous les caractères qui ne sont pas (-c
signifie complément) dans le jeu de caractères"\n
.la source
tr
&wc
.ß
(hex utf: c3 9F) ( au lieu de"
) fonctionne comme prévu, à savoirtr
,sed
etawk
ne compléter / remplacer / comptage sans problème - sur un système Ubuntu 10.04.tr
, y compris GNU tr et classic Unix tr, fonctionnent sur des caractères à un octet et ne sont pas compatibles avec Unicode .. Cité sur Wikipedia tr (Unix) .. Essayez cet extrait:echo "aā⧾c" | tr "ā⧾" b
... sur Ubuntu 10.04 ...ß
est un seul octet Le caractère latin étendu est traité partr
... Le vrai problème ici n’est pas quetr
Unicode ne soit pas géré (car TOUS les caractères sont Unicode), c’est vraiment quetr
seul un octet à la fois estJe voudrais juste utiliser awk
Ici, nous définissons le séparateur de champ (avec l'indicateur -F) comme étant le caractère,
"
puis tout ce que nous faisons est d'imprimer le nombre de champsNF
- 1. Le nombre d'occurrences du caractère cible sera égal à un de moins que le nombre de champs séparés.Pour les personnages amusants interprétés par le shell, vous devez simplement vous assurer de les échapper, sinon la ligne de commande essaiera de les interpréter. Donc, pour les deux
"
et)
vous devez échapper au séparateur de champ (avec\
).la source
'
). En outre, il a un comportement étrange avec des lignes vides."
donc je me sens obligé de faire fonctionner le code avec elle. Cela dépend de la coquille que vous utilisez si le personnage doit être échappé, mais bash / tcsh devront s'échapper tous les deux "-F'"'
.awk -F"$1" '{print NF==0?NF:NF-1}' filename
En utilisant
tr
ardwc
:Usage:
la source
tr
ne gère pas les caractères qui utilisent plus d'un octet .. voir Wikipedia tr (Unix) .. ie.tr
n'est pas conforme à Unicode.$IFS
, sinon vousread
devrez les rogner du début à la fin.echo
pour des données arbitrairestr
implémentations prennent en charge les caractères multi-octets, maiswc -c
comptent des octets, pas des caractères quand même (nécessitéwc -m
de caractères).Une autre mise en œuvre qui ne repose pas sur des programmes externes, dans
bash
,zsh
,yash
et certaines implémentations / versions deksh
:Utilisez
line="${line//[!(]}"
pour compter(
.la source
eof=false; IFS=; until $eof; do read -r || eof=true; echo "$REPLY"; done
/
qui n'est pas nécessaire dans bash. C'est une exigence de ksh?/
est nécessaire dans les anciennes versions de ksh, et IIRC dans les anciennes versions de bash.Les réponses à l'aide
awk
échouent si le nombre de correspondances est trop grand (ce qui est mon cas). Pour la réponse de loki-astari , l'erreur suivante est signalée:Pour la réponse de enzotib (et l’équivalent de manatwork ), une erreur de segmentation se produit:
La
sed
solution de maxschlepzig fonctionne correctement, mais est lente (timings ci-dessous).Certaines solutions pas encore suggérées ici. Tout d'abord, en utilisant
grep
:Et en utilisant
perl
:Voici quelques timings pour quelques solutions (ordonnées du plus lent au plus rapide); J'ai limité les choses à une ligne ici. 'foo.txt' est un fichier avec une ligne et une longue chaîne contenant 849 correspondances.
la source
Une autre
awk
solution:la source
Une autre implémentation possible avec awk et gsub:
La fonction
gsub
est l'équivalent de sed's///g'
.Utilisez
gsub("[^(]", "")
pour compter(
.la source
awk '{print gsub(/"/,"")}' input-file
serait suffisant, comme "Pour chaque sous-chaîne correspondant à l'expression régulière r dans la chaîne t, remplacez la chaîne s et renvoyez le nombre de substitutions." (man awk)J'ai décidé d'écrire un programme C parce que je m'ennuyais.
Vous devriez probablement ajouter une validation d'entrée, mais à part cela, tout est défini.
la source
free(line)
omettre car la sortie du programme libère implicitement toute la mémoire allouée - alors il y a de la place pour unreturn 0;
...;). Même dans les exemples, il n'est pas bon de laisser le code de retour non défini. Btw,getline
est une extension GNU - au cas où quelqu'un se le demanderait.f
, appelée plusieurs fois à partir d'un autre code, vous devez appelerfree
après le dernier appel degetline
à la fin de cette fonctionf
.Pour une chaîne, le plus simple serait avec
tr
etwc
(pas besoin de trop utiliser avecawk
oused
) - mais notez les commentaires ci-dessus à propostr
, compte les octets, pas les caractères -où
$x
est la variable qui contient la chaîne (pas un fichier) à évaluer.la source
Voici une autre solution C qui nécessite uniquement STD C et moins de mémoire:
la source
\n
n'est pas une vraie ligne. C'est le même comportement qu'avec mon autre réponse sed / awk (tr / awk).Nous pouvons utiliser
grep
avecregex
pour le rendre plus simple et puissant.Compter un caractère spécifique.
Compter les caractères spéciaux, y compris les espaces.
Ici, nous sélectionnons n’importe quel caractère avec
[\S\s]
et avec la-o
possibilitégrep
d’imprimer chaque correspondance (c’est-à-dire chaque caractère) sur une ligne distincte. Et puis utilisezwc -l
pour compter chaque ligne.la source
"
sont dans chaque ligne; et pour tous les autres personnages. voir sa question et a également accepté la réponse.Peut-être qu'une réponse plus simple, purement awk, serait d'utiliser la scission. Split prend une chaîne et la transforme en tableau, la valeur de retour est le nombre d'éléments de tableau générés + 1.
Le code suivant affichera le nombre de fois "apparaît sur chaque ligne.
plus d'infos sur le split http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html
la source
Voici un script Python simple pour trouver le nombre de
"
dans chaque ligne d'un fichier:Ici, nous avons utilisé la
count
méthode du type intégréstr
.la source
Pour une solution pure bash (cependant, elle est spécifique à bash): If
$x
est la variable contenant votre chaîne:La
${x//
chose supprime tous les caractères sauf"
,${#x2}
calcule la longueur de ce repos.(Suggestion originale en utilisant
expr
qui a des problèmes, voir les commentaires:)la source
expr
et compte octets, pas de caractères. Avec d'autresexpr
:expr "x${x...}" : "x.*" - 1
Remplacer
a
par le caractère à compter. La sortie est le compteur pour chaque ligne.la source
Comparaison dans le temps des solutions présentées (pas une réponse)
L'efficacité des réponses n'est pas importante. Néanmoins, après l’approche @josephwb, j’ai essayé de chronométrer toutes les réponses présentées.
J'utilise comme entrée la traduction portugaise de Victor Hugo "Les Misérables" (grand livre!) Et compte les occurrences de "a". Mon édition a 5 volumes, plusieurs pages ...
Les réponses en C ont été compilées avec gcc, sans optimisation.
Chaque réponse a été exécutée 3 fois et choisissez le meilleur.
Ne faites pas trop confiance à ces chiffres (ma machine effectue d'autres tâches, etc.). Je partage ces moments avec vous, car j’ai eu des résultats inattendus et je suis sûr que vous en trouverez d’autres ...
grep -oP a
est l'arbre fois plus vite quegrep -o a
(10; 11 vs 12)(résultats dans un ordre aléatoire)
la source
où grep fait le gros du travail: rapporte chaque caractère trouvé à chaque numéro de ligne. Le reste consiste simplement à additionner le nombre par ligne et à formater la sortie.
Supprimez le
-n
et obtenez le nombre pour le fichier entier.Compter un fichier texte 1,5Meg en moins de 0,015 seconde semble rapide.
Et fonctionne avec des caractères (pas des octets).
la source
Une solution pour bash. Aucun programme externe appelé (plus rapide pour les chaînes courtes).
Si la valeur est dans une variable:
Cela imprimera combien
"
il contient:la source