2017-02-21 13 views
3

Я пытаюсь обрабатывать некоторые данные, но я не могу найти рабочее решение для своей проблемы. У меня есть файл, который выглядит как:Удаление строк с более чем 30% строчными буквами

>ram 
cacacacacacacacacatatacacatacacatacacacacacacacacacacacacaca 
cacacacacacacaca 
>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 
>sam 
AATTGGCCAATTGGCAATTCCGGAATTCaattggccaattccggaattccaattccgg 

and many lines more.... 

Я хочу, чтобы отфильтровать все строки и соответствующие заголовки (заголовок начинается с>), где строка последовательности (те, которые не начинаются с>) является содержащими 30 или более процентами строчные буквы. И последовательности строк могут охватывать несколько строк.

Таким образом, после команды ху вывод должен выглядеть следующим образом:

>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 

Я пробовал некоторые микс из цикла в то время как для чтения входного файла, а затем работать с AWK, Grep, СЭД, но не было хорошим результатом.

+3

Вы попытались и не смогли это сделать? покажите нам свои усилия. – Inian

+0

Также 'bash' не подходит для этого, так как он не может оценить значение с плавающей запятой для вычисления и сравнения.Вы можете очень хорошо удалить тег 'bash' – Inian

ответ

2

Или:

awk '{n=length(gensub(/[A-Z]/,"","g"));if(NF && n/length*100 < 30)print a $0;a=RT}' RS='>[a-z]+\n' file 
  1. RS='>[a-z]+\n' - Устанавливает разделитель в строке, содержащей «> 'и название

  2. RT - это значение устанавливается, что подобрано RS выше

  3. a=RT - сохранить предыдущее значение RT

  4. n=length(gensub(/[A-Z]/,"","g")); - получить длину нижнего случае обугливается

  5. if(NF && n/length*100 < 30)print a $0; - проверить у нас есть значение и что процент меньше 30 для символов нижнего регистра

+0

'gawk' только, но красиво сделано. Может быть, добавить некоторые объяснения. – dawg

+0

спасибо. Это работает, и ваше описание очень приятно и помогает мне понять, что происходит. – JFS31

4

Вот одна идея, которая устанавливает разделитель записей в «>», чтобы обрабатывать каждый заголовок с его строками последовательности в виде одной записи.

Поскольку ввод начинается с символа «>», который вызывает начальную пустую запись, мы берем вычисление с помощью NR > 1 (номер записи больше одного).

Чтобы подсчитать количество символов, мы добавляем длины всех строк после заголовка. Чтобы подсчитать количество символов в нижнем регистре, мы сохраняем строку в другой переменной и используем gsub для замены всех строчных букв ничем --- только потому, что gsub возвращает количество сделанных замещений, что является удобным способом подсчета их.

Наконец, мы проверяем соотношение и печатаем или нет (добавление начального «>» при печати).

BEGIN { RS = ">" } 

NR > 1 { 
    total_cnt = 0 
    lower_cnt = 0 
    for (i=2; i<=NF; ++i) { 
     total_cnt += length($i) 
     s = $i 
     lower_cnt += gsub(/[a-z]/, "", s) 
    } 
    ratio = lower_cnt/total_cnt 
    if (ratio < 0.3) print ">"$0 
} 


$ awk -f seq.awk seq.txt 
>pam 
GAATGTCAAAAAAAAAAAAAAAAActctctct 
+0

Включите заголовок в подсчет? – ceving

+0

Обратите внимание, что строка, начинающаяся с символа '>', не должна учитываться, поскольку она не является частью строки последовательности. –

+0

Нет, я не смотрю на символы в заголовке и не подсчитываю их при вычислении отношения. (Вот почему цикл for начинается с i = 2) – jas

1
awk '/^>/{b=B;gsub(/[A-]/,"",b); 
      if(length(b) < length(B) * 0.3) print H "\n" B 
      H=$0;B="";next} 

    {B=((B != "") ? B "\n" : "") $0} 

    END{ b=B;gsub(/[A-]/,"",b); 
      if(length(b) < length(B) * 0.3) print H "\n" B 
     }' YourFile 

быстро Qnd грязный, функция люкс лучше потребность для печати

+0

Благодарим вас за ответ. Это выглядит действительно причудливо, и я постараюсь, чтобы что-то там происходило. – JFS31

1

В настоящее время я не буду использовать sed или awk больше ни на что большее, чем на 2 линии.

#! /usr/bin/perl 
use strict;        # Force variable declaration. 
use warnings;        # Warn about dangerous language use. 

sub filter         # Declare a sub-routing, a function called `filter`. 
{ 
    my ($header, $body) = @_;    # Give the first two function arguments the names header and body. 
    my $lower = $body =~ tr/a-z//;   # Count the translation of the characters a-z to nothing. 
    print $header, $body, "\n"    # Print header, body and newline, 
    unless $lower/length ($body) > 0.3; # unless lower characters have more than 30%. 
} 

my ($header, $body);      # Declare two variables for header and body. 
while (<>) {        # Loop over all lines from stdin or a file given in the command line. 
    if (/^>/) {        # If the line starts with >, 
    filter ($header, $body)    # call filter with header and body, 
     if defined $header;     # if header is defined, which is not the case at the beginning of the file. 
    ($header, $body) = ($_, '');   # Assign the current line to header and an empty string to body. 
    } else { 
    chomp;         # Remove the newline at the end of the line. 
    $body .= $_;       # Append the line to body. 
    } 
} 
filter ($header, $body);     # Filter the last record. 
+0

Спасибо за ваш ответ, но, к сожалению, я никогда не работал с Perl. Поэтому я не в состоянии понять ваш код. И решение, которое я могу понять и изменить, если захочу, как в awk или sed, лучше подходит для моих потребностей. – JFS31

+0

@ JFS31 Я добавил несколько комментариев. Может быть, это хороший пример, чтобы узнать что-то новое. – ceving

+0

Thats very nice. Я посмотрю и попытаюсь что-то получить от него :) – JFS31