¿Cómo contar el número de caracteres en una línea, excepto un carácter específico?

9

Este es un archivo parcial

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

En cada línea quiero contar el número total de todos los caracteres que no son "N"

mi deseo de salida

1
1
1
0
1
2
2
Anna1364
fuente
Úselo sedpara reemplazar cosas que no le interesan y awkpara contar la longitud restantesed 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf

Respuestas:

13

Solución GNU awk :

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- el patrón que define un valor de campo (cualquier carácter excepto caracteres Ny espacios en blanco)

El resultado esperado:

1
1
1
0
1
2
2
RomanPerekhrest
fuente
9
awk '{ gsub("[ N]",""); print length() }'
Hauke ​​Laging
fuente
también puede usarawk '{print gsub(/[^ N]/,"")}'
Sundeep
7

suponiendo que se necesita un recuento para cada línea que no sea el carácter de espacio y N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • el valor de retorno de tres cuántos caracteres fueron reemplazados
  • c para complementar el conjunto de caracteres dados
  • Tenga en cuenta el uso de la -lopción, elimina el carácter de nueva línea de la línea de entrada para evitar un error fuera de uno y también agrega el carácter de nueva línea para la instrucción de impresión


Una solución más genérica

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aopción para dividir automáticamente la línea de entrada en espacios en blanco, guardada en una @Fmatriz
  • grep {$_ ne "N"} @Fdevuelve una matriz de todos los elementos en los @Fque no coincide con la cadenaN
    • equivalente regex sería grep {!/^N$/} @F
  • el uso de scalardará un número de elementos de la matriz
Sundeep
fuente
6

Solución alternativa awk :

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- La gsub()función devuelve el número de sustituciones realizadas.

La salida:

1
1
1
0
1
2
2
RomanPerekhrest
fuente
6

Otro awkenfoque (devolverá -1 para líneas vacías).

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

O en complejo, devolverá -1 en líneas vacías, 0 en líneas de espacios en blanco (tabulaciones / espacios) solamente.

awk -F'[^N \t]+' '$0=NF-1""' infile
αғsнιη
fuente
se imprimirá -1para líneas vacías ... pero eso podría ser deseable para distinguir una línea compuesta solo de N / espacio frente a una línea vacía ...
Sundeep
1
@Sundeep Sí, eso es correcto. También vea mi actualización donde las líneas solo contienen pestañas o espacios para indicar como 0
αғsнιη
5
  1. try script de shell POSIX :

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

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    
agc
fuente
1
puede usar awk '{print length()}'para evitar el bucle de shell más lento ... pero entonces uno podría hacerlo todo con awk en sí ...
Sundeep
@Sundeep, es cierto, ( si ambos se inician al mismo tiempo), ese awkbucle es más rápido que el bucle de shell. Pero el shell siempre está en la memoria, y awkpuede que no lo esté: cuando awkno está cargado o intercambiado, la sobrecarga de cargarlo ( el tiempo perdido ) puede ser mayor que la ventaja de correr awk, particularmente en un pequeño lazo. En tales casos, ( es decir, este caso), awkpuede ser más lento .
agc
bueno, ciertamente no me preocupa el tiempo para cosas pequeñas ... ver unix.stackexchange.com/questions/169716/…
Sundeep
1
@Sundeep, yo hago la preocupación. Hace algún tiempo, solía usar distribuciones de Linux basadas en disquete , que podrían ejecutarse en un disquete, en unos pocos megas de ram. El uso innecesario awken un script de shell podría hacer que dicho sistema se arrastre a cuatro patas. En general: el mismo arrastre de latencia se aplica a los sistemas con firmware limitado, o cualquier sistema bajo carga pesada.
agc
1

Una breve combinación de try awk:

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

Esto elimina todos los espacios y N del archivo de entrada y awksolo imprime la longitud de cada línea.

Kusalananda
fuente
0

Otra forma fácil es hacerlo en Python, que viene preinstalado en la mayoría de los entornos Unix. Coloque el siguiente código en un archivo .py:

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

Y luego hacer:

python file.py

Desde tu terminal. Lo que hace lo anterior es:

  • para cada línea en un archivo llamado "geno"
  • pon un contador a 0 e increméntalo cada vez que encontremos un valor! = 'N'
  • Cuando se alcanza el final de la línea actual, imprima el contador y pase a la línea siguiente.
Grajdeanu Alex.
fuente