Cara menghitung kemunculan suatu pola dalam suatu garis

8

Saya punya file yang memiliki tiga kolom. Kolom 3 berisi nama-nama gen dan terlihat seperti ini:

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

Bagaimana saya bisa mencetak jumlah gen di setiap baris?

Saisha
sumber
Kolom keempat? Apa yang harus terjadi jika kolom tersebut sudah ditempati (baris kedua dalam contoh Anda), atau jika kolom lainnya kosong (baris terakhir)?
Kusalananda
@ Kusalananda Dihapus kriteria itu dari permintaan saya :)
Saisha
Pada tampilan cepat, semua jawaban menghitung bidang yang dipisahkan tanda koma atau string yang cocok dengan Rv*pola di mana saja pada baris, tidak hanya di kolom tertentu. Jadi saya hanya akan mencatat bahwa jika Anda benar-benar memiliki data lain dalam file tersebut, tidak disajikan dalam pertanyaan di sini, Anda mungkin perlu memodifikasi solusinya. (Atau jelaskan pertanyaannya.)
ilkkachu

Jawaban:

10

Anda hanya ingin menambahkan kolom dengan jumlah kolom di dalamnya. Ini dapat dilakukan dengan menggunakan awk:

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

NFadalah awkvariabel yang berisi jumlah bidang (kolom) dalam catatan saat ini (baris). Kami mencetak nomor ini diikuti dengan koma dan sisa baris, untuk setiap baris.

Alternatif (hasil yang sama, tetapi mungkin terlihat sedikit lebih bersih):

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

FSadalah pemisah bidang yang awkdigunakan untuk membagi setiap rekaman menjadi bidang, dan kami menyetelnya menjadi koma dengan -F ','pada baris perintah (seperti pada solusi pertama). OFSadalah pemisah bidang keluaran , dan kami menetapkan agar sama dengan FSsebelum membaca baris input pertama.

Kusalananda
sumber
5

Jika Anda ingin menghitung jumlah kemunculan Rv[0-9]{4}c?pola yang bertentangan dengan jumlah bidang yang dibatasi koma seperti yang disarankan subjek Anda, Anda dapat melakukan:

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

Pendekatan Perl:

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

The -amerek perlberperilaku seperti awkdan membagi setiap baris masukan pada string yang diberikan oleh -Fdan menyimpan bidang yang dihasilkan ke dalam array @F. Oleh karena itu, $#Fakan menjadi indeks array tertinggi di @Fdan, sejak array mulai menghitung 0, $#F+1akan menjadi jumlah total elemen dalam array. The -pberarti "mencetak setiap baris masukan setelah aplpying script yang diberikan oleh -e. The s///adalah operator substitusi dan di sini yang menggantikan awal dari garis ( ^) dengan jumlah bidang + 1 dan koma ( $#F+1 . ",").

terdon
sumber
1

Pertanyaan Anda menyatakan bahwa kolom 3 berisi nama-nama gen. Saya berasumsi input aktual Anda adalah sebagai berikut:

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

Setiap nama gen di kolom3 berisi Rvsubstring terkemuka . Dengan demikian kita dapat menghitungnya dengan python:

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

Daftar yang dihasilkan menunjukkan jumlah gen di setiap baris, dalam urutannya masing-masing. Jika kita ingin membuatnya lebih verbose dan menyertakan kemungkinan bahwa gen mungkin tidak mengandung string "Rv" (tetapi pertahankan asumsi bahwa column3 adalah string nilai yang dipisah koma), kita juga dapat melakukan hal berikut:

#!/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))

Uji coba:

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