Cara mengekstrak beberapa bit informasi yang muncul pada baris berbeda di dalam file teks yang sama

8

Saya mencoba untuk mengekstrak ID urutan dan nomor cluster yang terjadi pada baris yang berbeda dalam file teks yang sama.

Inputnya seperti

>Cluster 72
0   319aa, >O311_01007... *
>Cluster 73
0   318aa, >1494_00753... *
1   318aa, >1621_00002... at 99.69%
2   318aa, >1622_00575... at 99.37%
3   318aa, >1633_00422... at 99.37%
4   318aa, >O136_00307... at 99.69%
>Cluster 74
0   318aa, >O139_01028... *
1   318aa, >O142_00961... at 99.69%
>Cluster 75
0   318aa, >O300_00856... *

Output yang diinginkan adalah ID urutan dalam satu kolom dan nomor cluster yang sesuai di kolom kedua.

>O311_01007  72
>1494_00753  73
>1621_00002  73
>1622_00575  73
>1633_00422  73
>O136_00307  73
>O139_01028  74
>O142_00961  74
>O300_00856  75

Adakah yang bisa membantu dengan ini?

Tim
sumber
Apakah ID urutan selalu menjadi bidang pisah ruang 3d pada garis yang tidak dimulai >? Juga, Anda mungkin tertarik dengan situs saudara kami, Bioinformatika .
terdon

Jawaban:

13

Dengan awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • kami membagi bidang pada spasi atau periode dengan -F '[. ]*'
  • dengan garis dua bidang, ( >Clustergaris), simpan bidang kedua sebagai ID dan pindah ke baris berikutnya
  • dengan baris lain, cetak bidang ketiga dan ID yang disimpan
muru
sumber
Daripada memilah jumlah bidang, mungkin lebih baik mencari secara eksplisit $1 == ">Cluster"daripada NF == 2bergantung pada apa lagi yang mungkin ada dalam file.
Monty Harder
5

Anda dapat menggunakan awkini:

awk '/>Cluster/{
      c=$2;
      next
    }{
      print substr($3,2,length($3)-4), c
    }' file

Pernyataan blok pertama adalah menangkap ID cluster. Pernyataan blok kedua (yang default) adalah mengekstraksi data yang diinginkan, dan mencetaknya.

oliv
sumber
Anda tidak perlu memberi " "argumen print. Cukup gunakan koma untuk memisahkan argumen dan itu akan menggunakan OFS, ruang default, untuk memisahkan argumen.
muru
4

Berikut ini alternatif dengan Ruby sebagai satu-baris:

ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file

atau menyebar pada beberapa baris:

ruby -ne 'case $_
when /^>Cluster (\d+)/
  id = $1
when /, (>\w{4}_\w{5})\.\.\./
  puts "#{$1} #{id}"
end' input_file

Saya kira itu hanya lebih mudah dibaca daripada awkversi jika Anda tahu Ruby dan regexen. Sebagai bonus, kode ini mungkin sedikit lebih kuat daripada hanya memisahkan garis, karena mencari teks di sekitarnya.

Eric Duminil
sumber
1

Perl:

$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Penjelasan

  • perl -ne: baca input file baris per baris ( -n) dan terapkan skrip yang diberikan oleh -euntuk setiap baris.
  • if(/^>.*?(\d+)/){$n=$1;}: jika baris ini dimulai dengan a >, cari rentangan angka terpanjang di akhir baris, dan simpan sebagai $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: jika garis tidak dimulai dengan >, gantikan semuanya dengan bentangan non- .karakter paling panjang setelah a >( >[^.]+), yaitu nama urutan ( $1karena kami telah menangkap pertandingan regex) dan nilai saat ini dari $n.

Atau, untuk pendekatan yang lebih mirip canggung:

$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Ini hanya cara yang sedikit lebih rumit untuk melakukan ide dasar yang sama dengan berbagai awkpendekatan. Saya memasukkannya untuk penyelesaian dan untuk penggemar Perl. Jika Anda membutuhkan penjelasan, gunakan saja solusi awk :).

terdon
sumber