«Мотив» здесь представляет собой любую длинную комбинацию символов [HKR]; мотивы могут совпадать.
Перекрытие разрешается с помощью «заглядывания» в регулярное выражение. Подробности смотрите ниже. Похоже, что ни один из цитируемых или показанных ресурсов не справляется с этим, и я не вижу, как они уловили бы перекрывающиеся мотивы.
use warnings;
use strict;
use feature 'say';
my $file = shift || die "Usage: $0 fasta-file\n";
open my $fh, '<', $file or die "Can't open $file: $!";
my ($seq, $seq_name);
while (<$fh>) {
chomp;
if (/^>(.*)/) {
# Process the previous assembled sequence
if ($seq) {
proc_seq($seq_name, $seq);
$seq = '';
}
$seq_name = $1;
next;
}
$seq .= $_;
}
# Process the last one
proc_seq($seq_name, $seq);
sub proc_seq {
my ($seq_name, $seq, $multiline) = @_;
# Build output in the loop, as motifs are found. By default, print all
# output for one seq_name in one line. To print each motif on its own
# line instead, invoke this sub with a true third argument (1 will do).
my $output = ">$seq_name";
my $cnt = 0;
while ($seq =~ /([HKR])(?=([HKR]{2}))/g) {
++$cnt;shot/
my $motif = $1 . $2;
my $pos = pos($seq);
my $pre_context = ($pos >= 11)
? substr($seq, $pos-11, 10)
: substr($seq, 0, $pos-1);
my $post_context = substr $seq, $pos+2, 10;
$output .= " n$cnt($pos~" . ($pos+2) . ") ";
$output .= "\n" if $multiline;
$output .= lc($pre_context) . $motif . lc($post_context);
}
say ($cnt > 0 ? $output : $output . ' no match found');
}
Примечание к регулярному выражению: нам нужен прогноз для второго и третьего символа, чтобы иметь возможность также поймать перекрывающиеся мотивы.
Пример. В первой последовательности HHKK
с перекрывающимися мотивами HHK
и HKK
. Если регулярное выражение соответствует HHK
с использованием /[HKR]{3}/
, то после этого положение механизма регулярных выражений в строке будет после первого K
, так как оно «потребляется» HHK
. Таким образом, все, что он может видеть дальше, это только один K
, и поэтому нет [HKR]{3}
, чтобы соответствовать следующему, и поэтому он пропускает следующий мотив.
Итак, вместо этого я сопоставляю только одну букву и делаю «заглядывание» для следующих двух. Затем после сопоставления H
(и «увидев», что действительно HK
следует) только одна буква расходуется, и двигатель прошел только эту первую H
, и она позиционируется перед второй H
для следующей матч. Теперь он сможет в следующий раз сопоставить HKK
таким же образом (и, таким образом, он сможет сопоставлять даже многократно перекрывающиеся мотивы).
Это идентифицирует все, что указано в желаемом выводе (который имеет опечатку); обратите внимание на изменение требований в комментарии, чтобы напечатать все мотивы для одной последовательности в одной строке. Так что печатает
>NP_001002156.1 n1(7~9) mktavdRRKldllysrykd n2(148~150) lglwntflleHHKksipkdtwnl n3(149~151) glwntfllehHKKsipkdtwnll
>NP_957070.2 n1(163~165) schvydqkniRRRvydalnvlma
>NP_bogus_with_no_motifs no match found
со всеми мотивами для одного и того же имени последовательности в одной строке, как и хотелось. Я добавил фиктивную строку для ввода без мотивов, чтобы проверить добавление no match found
; это нарисовало последнюю строку в выводе выше.
По-прежнему есть возможность печатать каждый мотив на отдельной строке, как это было первоначально необходимо: вызвать функцию proc_seq
с дополнительным третьим аргументом, который имеет значение true, например,
proc_seq($seq_name, $seq, 1)
и тогда он напечатает
>NP_001002156.1 n1(7~9)
mktavdRRKldllysrykd n2(148~150)
lglwntflleHHKksipkdtwnl n3(149~151)
glwntfllehHKKsipkdtwnll
>NP_957070.2 n1(163~165)
schvydqkniRRRvydalnvlma
>NP_bogus_with_no_motifs no match found