Cách trích xuất nhiều bit thông tin xuất hiện trên các dòng khác nhau trong cùng một tệp văn bản


8

Tôi đang cố gắng trích xuất ID chuỗi và số cụm xảy ra trên các dòng khác nhau trong cùng một tệp văn bản.

Đầu vào trông giống như

>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... *

Đầu ra mong muốn là ID chuỗi trong một cột và số cụm tương ứng trong giây.

>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

Bất cứ ai có thể giúp đỡ với điều này?


Có phải ID trình tự sẽ luôn là trường được phân tách không gian 3d trên các dòng không bắt đầu bằng >? Ngoài ra, bạn có thể quan tâm đến trang web chị em của chúng tôi, Tin sinh học .
terdon 26/03/18

Câu trả lời:


13

Với awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • chúng tôi chia các trường trên không gian hoặc dấu chấm với -F '[. ]*'
  • với các dòng của hai trường, (các >Clusterdòng), lưu trường thứ hai làm ID và di chuyển đến dòng tiếp theo
  • với các dòng khác, in trường thứ ba và ID đã lưu

Thay vì khóa số lượng trường, có thể tốt hơn là tìm kiếm $1 == ">Cluster"thay vì NF == 2, tùy thuộc vào những gì khác có thể có trong tệp.
Monty Harder

5

Bạn có thể sử dụng awkcho việc này:

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

Câu lệnh chặn đầu tiên là chụp ID cụm. Câu lệnh khối thứ hai (mặc định) đang trích xuất dữ liệu mong muốn và in nó.


Bạn không cần phải đưa ra " "như là một đối số print. Chỉ cần sử dụng dấu phẩy để phân tách các đối số và nó sẽ sử dụng OFS, không gian mặc định, để phân tách các đối số.
muru

4

Đây là một thay thế với Ruby như một lớp lót:

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

hoặc trải rộng trên nhiều dòng:

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

Tôi đoán nó chỉ dễ đọc hơn awkphiên bản nếu bạn biết Ruby và regexen. Như một phần thưởng, mã này có thể mạnh hơn một chút so với việc chia dòng đơn giản, bởi vì nó tìm kiếm văn bản xung quanh.


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

Giải trình

  • perl -ne: đọc dòng tệp đầu vào theo dòng ( -n) và áp dụng tập lệnh được cung cấp -echo từng dòng.
  • if(/^>.*?(\d+)/){$n=$1;}: nếu dòng này bắt đầu bằng a >, hãy tìm đoạn số dài nhất ở cuối dòng và lưu nó dưới dạng $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: nếu dòng không bắt đầu bằng >, hãy thay thế mọi thứ bằng đoạn không dài nhất của .ký tự theo sau >( >[^.]+), tức là tên chuỗi ( $1vì chúng tôi đã bắt được kết quả khớp chính thức) và giá trị hiện tại của $n.

Hoặc, đối với cách tiếp cận giống như awk hơn:

$ 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

Đây chỉ là một cách rườm rà hơn một chút để thực hiện cùng một ý tưởng cơ bản như các awkcách tiếp cận khác nhau . Tôi bao gồm nó vì mục đích hoàn thành và cho người hâm mộ Perl. Nếu bạn cần một lời giải thích, chỉ cần sử dụng các giải pháp awk :).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.