Cómo contar la aparición de un patrón en una línea

8

Tengo un archivo que tiene tres columnas. La columna 3 contiene nombres de genes y se ve así:

Rv0729,Rv0993,Rv1408  
Rv0162c,Rv0761c,Rv1862,Rv3086  
Rv2790c

¿Cómo puedo imprimir el número de genes en cada fila?

Saisha
fuente
¿Una cuarta columna? ¿Qué debería suceder si esa columna ya está ocupada (segunda fila en su ejemplo), o si las otras columnas están vacías (última fila)?
Kusalananda
@Kusalananda eliminó ese criterio de mi consulta :)
Saisha
En un vistazo rápido, todas las respuestas cuentan los campos separados por comas o cadenas que coinciden con el Rv*patrón en cualquier lugar de la línea, no solo en una columna en particular. Así que solo notaré que si realmente tiene otros datos en el archivo, no presentados en la pregunta aquí, es posible que deba modificar las soluciones en consecuencia. (O aclarar la pregunta.)
ilkkachu

Respuestas:

10

Simplemente desea agregar una columna con el recuento de columnas en ella. Esto se puede hacer usando awk:

$ awk -F ',' '{ printf("%d,%s\n", NF, $0) }' data.in
3,Rv0729,Rv0993,Rv1408
4,Rv0162c,Rv0761c,Rv1862,Rv3086
1,Rv2790c

NFes una awkvariable que contiene el número de campos (columnas) en el registro actual (fila). Imprimimos este número seguido de una coma y el resto de la fila, para cada fila.

Una alternativa (el mismo resultado, pero puede parecer un poco más limpio):

$ awk -F ',' 'BEGIN { OFS=FS } { print NF, $0 }' data.in

FSes el separador de campo que se awkusa para dividir cada registro en campos, y lo configuramos como una coma -F ','en la línea de comando (como en la primera solución). OFSes el separador de campo de salida , y configuramos que sea el mismo que FSantes de leer la primera línea de entrada.

Kusalananda
fuente
5

Si desea contar el número de apariciones del Rv[0-9]{4}c?patrón en lugar del número de campos delimitados por comas como sugiere el tema de su pregunta, puede hacer lo siguiente:

 awk '{print gsub(/Rv[0-9]{4}c?/, "&"), $0}'
Stéphane Chazelas
fuente
4

Un enfoque de Perl:

$ perl -F, -pae 's/^/$#F+1 . ","/e' file
3,Rv0729,Rv0993,Rv1408  
4,Rv0162c,Rv0761c,Rv1862,Rv3086  
1,Rv2790c

Las -amarcas se perlcomportan como awky dividen cada línea de entrada en la cadena dada por -Fy guardan los campos resultantes en la matriz @F. Por lo tanto, $#Fserá el índice de matriz más alto @Fy, dado que las matrices comienzan a contar en 0, $#F+1será el número total de elementos en la matriz. El -pmedio "imprime cada línea de entrada después de aplicar la secuencia de comandos dada por -e. El s///es el operador de sustitución y aquí reemplazamos el comienzo de la línea ( ^) con el número de campos + 1 y una coma ( $#F+1 . ",").

terdon
fuente
1

Su pregunta establece que la columna 3 contiene nombres de genes. Supongo que su entrada real es la siguiente:

column1 column2 Rv0729,Rv0993,Rv1408  
column1 column2 Rv0162c,Rv0761c,Rv1862,Rv3086  
column1 column2 Rv2790c

Cada nombre de gen en la columna 3 contiene una Rvsubcadena principal . Por lo tanto, podemos contarlos en Python así:

$ python -c  "import sys;print map(lambda x: x.split()[2].count('Rv'),sys.stdin.readlines())"  < input.txt               
[3, 4, 1]

La lista resultante muestra el recuento de genes en cada línea, en su orden respectivo. Si queremos hacerlo más detallado e incluir la posibilidad de que los genes no contengan la cadena "Rv" (pero supongamos que column3 es una cadena de valores separados por comas), también podemos hacer lo siguiente:

#!/usr/bin/env python
import sys
with open(sys.argv[1]) as fd:
    for index,line in enumerate(fd):
        columns = line.strip().split()
        num_genes=len(columns[2].split(","))
        print("Line "+str(index)+" contains "+str(num_genes))

Prueba de funcionamiento:

$ ./count_genes.py input.txt                                                                                             
Line 0 contains 3
Line 1 contains 4
Line 2 contains 1
Sergiy Kolodyazhnyy
fuente