Comment compter le nombre de caractères dans une ligne, sauf un caractère spécifique?

9

Ceci est un fichier partiel

N W N N N N N N N N N
N C N N N N N N N N N
N A N N N N N N N N N
N N N N N N N N N N N
N G N N N N N N N N N
N C N N N C N N N N N
N C C N N N N N N N N

Dans chaque ligne, je veux compter le nombre total de tous les caractères qui ne sont pas "N"

ma sortie désirée

1
1
1
0
1
2
2
Anna1364
la source
Utilisez sedpour remplacer les trucs qui ne vous intéressent pas et awkpour compter la longueur restantesed 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf

Réponses:

13

Solution GNU awk :

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- le motif définissant une valeur de champ (n'importe quel caractère sauf Nchar et blanc)

La sortie attendue:

1
1
1
0
1
2
2
RomanPerekhrest
la source
9
awk '{ gsub("[ N]",""); print length() }'
Hauke ​​Laging
la source
peut également utiliserawk '{print gsub(/[^ N]/,"")}'
Sundeep
7

en supposant que le comptage est nécessaire pour chaque ligne autre que le caractère espace et N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • la valeur de retour de trest le nombre de caractères remplacés
  • c pour compléter l'ensemble de caractères donné
  • Notez l'utilisation de l' -loption, supprime le caractère de nouvelle ligne de la ligne d'entrée pour éviter les erreurs hors ligne et ajoute également un caractère de nouvelle ligne pour l'instruction d'impression


Une solution plus générique

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aoption pour diviser automatiquement la ligne d'entrée sur les espaces blancs, enregistrée dans le @Ftableau
  • grep {$_ ne "N"} @Frenvoie un tableau de tous les éléments dans @Flesquels ne correspond pas à la chaîneN
    • équivalent regex serait grep {!/^N$/} @F
  • l'utilisation de scalardonnera le nombre d'éléments du tableau
Sundeep
la source
6

Solution alternative awk :

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- La gsub()fonction renvoie le nombre de substitutions effectuées.

Le résultat:

1
1
1
0
1
2
2
RomanPerekhrest
la source
6

Une autre awkapproche (retournera -1 pour les lignes vides).

awk -F'[^N ]' '$0=NF-1""' infile

Ou en complexe, il renverra -1 sur les lignes vides, 0 sur les espaces blancs (tabulations / espaces) uniquement.

awk -F'[^N \t]+' '$0=NF-1""' infile
αғsнιη
la source
imprimera -1pour les lignes vides ... mais alors cela pourrait être souhaitable pour distinguer la ligne composée uniquement de N / espace par rapport à la ligne vide ...
Sundeep
1
@Sundeep Oui, c'est exact. voir également ma mise à jour où les lignes ne contiennent que des tabulations ou des espaces pour indiquer 0
αғsнιη
5
  1. tret script shell POSIX :

    tr -d 'N ' < file | while read x ; do echo ${#x} ; done
    
  2. bash,, kshet zsh:

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    
agc
la source
1
peut utiliser awk '{print length()}'pour éviter le bouclage plus lent du shell .. mais alors on pourrait tout faire avec awk lui-même ...
Sundeep
@Sundeep, C'est vrai, ( si les deux sont démarrés en même temps), cette awkboucle est plus rapide que la boucle shell. Mais le shell est toujours en mémoire, et awkpeut-être pas - lorsqu'il awkn'est pas déjà chargé, ou échangé, la surcharge de chargement, ( le temps perdu ), peut être supérieure à l'avantage de l'exécution awk- en particulier sur un petit boucle. Dans de tels cas ( c'est-à - dire dans ce cas), awkpeut être plus lent .
agc
eh bien, je ne suis certainement pas inquiet du temps pour les petits trucs ... voir unix.stackexchange.com/questions/169716/…
Sundeep
1
@Sundeep, je ne vous inquiétez pas. Il y a quelque temps, j'utilisais des distributions Linux basées sur disquette , qui pouvaient fonctionner avec une disquette, en quelques Mo de RAM. Inutile d'utiliser awkdans un script shell pourrait faire un tel système à quatre pattes. Généralement: la même traînée de latence s'applique aux systèmes à micrologiciel limité ou à tout système soumis à une charge élevée.
agc
1

Une courte combinaison de tret awk:

$ tr -d ' N' <file.in | awk '{ print length }'
1
1
1
0
1
2
2

Cela supprime tous les espaces et N du fichier d'entrée et awkimprime simplement la longueur de chaque ligne.

Kusalananda
la source
0

Un autre moyen simple est de le faire en python, qui est pré-installé dans la plupart des environnements Unix. Déposez le code suivant dans un fichier .py:

with open('geno') as f:
    for line in f:
        count = 0
        for word in line.split():
            if word != 'N':
                count += 1
        print(count)

Et puis:

python file.py

Depuis votre terminal. Ce qui précède est:

  • pour chaque ligne d'un fichier nommé "geno"
  • mettre un compteur à 0 et l'incrémenter chaque fois que nous trouvons une valeur! = 'N'
  • lorsque la fin de la ligne actuelle est atteinte, imprimez le compteur et passez à la ligne suivante
Grajdeanu Alex.
la source