Come contare il numero di caratteri in una riga, tranne un carattere specifico?


9

Questo è un file di parti

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

In ogni riga voglio contare il numero totale di tutti i caratteri che non sono "N"

il mio desiderio di uscita

1
1
1
0
1
2
2

Usa sedper sostituire le cose che non ti interessano e awkper contare la lunghezza rimanentesed 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf,

Risposte:


13

GNU awk solution:

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- il modello che definisce un valore di campo (qualsiasi carattere tranne Nchar e spazi bianchi)

L'output previsto:

1
1
1
0
1
2
2


7

supponendo che il conteggio sia necessario per ogni riga diversa dal carattere spazio e N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • il valore restituito di trè il numero di caratteri sostituiti
  • c per completare il set di caratteri forniti
  • Nota l'uso -ldell'opzione, rimuove il carattere di nuova riga dalla riga di input per evitare errori off-by-one e aggiunge anche il carattere di nuova riga per l'istruzione print


Una soluzione più generica

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aopzione per dividere automaticamente la linea di input su spazi bianchi, salvata in @Farray
  • grep {$_ ne "N"} @Frestituisce la matrice di tutti gli elementi in @Fcui non corrisponde alla stringaN
    • equivalente regex sarebbe grep {!/^N$/} @F
  • l'uso di scalarfornirà il numero di elementi dell'array

6

Soluzione alternativa di awk :

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- La gsub()funzione restituisce il numero di sostituzioni effettuate.

Il risultato:

1
1
1
0
1
2
2

6

Un altro awkapproccio (restituirà -1 per le righe vuote).

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

O nel complesso, restituirà -1 su righe vuote, 0 solo su righe di spazi bianchi (Tab / Spaces).

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

stamperà -1per le righe vuote ... ma potrebbe essere desiderabile distinguere la riga composta da N / spazio solo rispetto alla riga vuota ...
Sundeep

1
@Sundeep Sì, è corretto. vedi anche il mio aggiornamento in cui le righe contenevano solo Schede o Spazi per indicare come 0
αғsнιη

5
  1. tre script shell POSIX :

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

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    

1
può usare awk '{print length()}'per evitare il looping della shell più lento .. ma poi si potrebbe fare tutto con awk stesso ...
Sundeep

@Sundeep, è vero, ( se entrambi vengono avviati contemporaneamente), il awklooping è più veloce del loop shell. Ma la shell è sempre in memoria e awkpotrebbe non esserlo - quando awknon è già caricata o scambiata, il sovraccarico di caricarla ( il tempo perso ) può essere maggiore del vantaggio dell'esecuzione awk- in particolare su un piccolo ciclo continuo. In tali casi, ( cioè questo caso), awkpuò essere più lento .
agc,

beh, non sono certo preoccupato del tempo per le piccole cose ... vedi unix.stackexchange.com/questions/169716/…
Sundeep

1
@Sundeep, io faccio preoccupazione. Qualche tempo fa usavo distribuzioni Linux basate su floppy , che potevano scappare da un floppy, in pochi mega di ram. L'uso inutile awkin uno script di shell potrebbe far sì che un tale sistema striscia a carponi. In generale: la stessa resistenza di latenza si applica ai sistemi con firmware limitato o a qualsiasi sistema sotto carico pesante.
agc,

1

Una breve combinazione di tre awk:

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

Questo elimina tutti gli spazi una Ns dal file di input e awkstampa solo la lunghezza di ogni riga.


0

Un altro modo semplice è farlo in Python, che viene preinstallato nella maggior parte degli ambienti unix. Rilascia il seguente codice in un file .py:

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

E poi fai:

python file.py

Dal tuo terminale Ciò che fa quanto sopra è:

  • per ogni riga in un file chiamato "geno"
  • imposta un contatore su 0 e incrementalo ogni volta che troviamo un valore! = 'N'
  • quando viene raggiunta la fine della riga corrente, stampare il contatore e passare alla riga successiva
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.