Как добавить данные 1-го столбца каждой строки в заголовок каждого столбца, помеченного определенной строкой или символами в соответствующей строке? - PullRequest
0 голосов
/ 04 января 2019

У меня большой кусок данных (один файл), как показано ниже, каждая строка имеет разное количество столбцов (разделенных табуляцией), структура данных похожа это:

>NP_12345.1 matchnumber_1_RKHKK 
>NP_56789.2 matchnumber_1_HGRR  matchnumber_2_KQRHH  matchnumber_3_RVRK matchnumber_4_HTHH
>XP_543421.1    matchnumber_1_RQRH  ... matchnumber_m_RVRR
...

В приведенном выше файле 1-я строка содержит 2 столбца, 2-я строка содержит 5 столбцов, а 3-я строка содержит m + 1 столбцов ...; Очевидно, что каждая строка файла имеет "> accessionID" и "matchnumber_i_XXX". Я хочу добавить 1-й столбец каждой строки к заголовку каждого столбца, помеченного "matchnumber" в соответствующей строке, и распечатать в формате fasta, вывод будет выглядеть так:

>NP_12345.1matchnumber_1
RKHKK   
>NP_56789.2matchnumber_1
HGRR    
>NP_56789.2matchnumber_2
KQRHH
>NP_56789.2matchnumber_3
RVRK
>NP_56789.2matchnumber_4
HTHH
>XP_543421.1matchnumber_1
RQRH
....
>XP_543421.1matchnumber_m
RVRR
...

Кто-нибудь может мне помочь? Заранее спасибо.

Примечание. Например, при наличии файла из одной строки файл "a.txt" содержит только одну строку:

>NP_56789.2 matchnumber_1_HGRR  matchnumber_2_KQRHH  matchnumber_3_RVRK matchnumber_4_HTHH

Я могу использовать команды piped awk и sed для анализа данных:

cat a.txt |awk -v OFS="\t" '{print $1$2,$1$3,$1$4,$1$5}' | sed 's/\t/\n/g' | sed 's/_/ /g' | sed 's/NP /NP_/g' | sed 's/matchnumber /matchnumber_/g' | sed 's/ /\n/g' > a.fasta

a.fasta - как мясо птицы:

>NP_56789.2matchnumber_1
HGRR
>NP_56789.2matchnumber_2
KQRHH
>NP_56789.2matchnumber_3
RVRK
>NP_56789.2matchnumber_4
HTHH

Когда a.txt содержит несколько строк этих данных, я понятия не имею, как решить проблему.

Ответы [ 6 ]

0 голосов
/ 05 января 2019

Это может сработать для вас (GNU sed):

sed -r ':a;h;/^(\S+)\s+(\S+)_(\S+)\s*(.*)/{s//\1\2\n\3/p;x;s//\1 \4/;ta};d' file

Сделать копию текущей строки. Используйте сопоставление с образцом, чтобы манипулировать первым и вторым полями в пространстве образца до требуемого формата и распечатать его. Перейдите к копии и сократите ее, удалив второе поле и все последующие пробелы. Повторяйте, пока сопоставление с образцом не удастся.

0 голосов
/ 05 января 2019

Следующее gawk (для расширения gensub) может работать для вас:

awk '{for(i=2;i<=NF;i++){print $1 gensub(/_([^_]+)$/,"\n\\1",1,$i)}}' file
0 голосов
/ 04 января 2019

Python плохо разбирается в однострочных командах, но с ним легко разобрать ваш файл:

parser.py:

import fileinput

for line in fileinput.input():     # process stdin or files given as parameters
    words = line.split()           # split the line
    for w in words[1:]:            # process all words past the first
        ix = w.rindex('_')         # search last _ in the words
        print(words[0] + w[:ix])   # print first line
        print(w[ix+1:])            # and second one

Затем вы можете использовать:

cat file | python parse.py

или

python parse.py file
0 голосов
/ 04 января 2019

Другой perl один вкладыш:

perl -anE '($c1,@r)=split/\s+/,$_;for(@r){($c,$v)=$_=~/^(.+)_(.+)$/;say "$c1 $c\n$v"}' file.txt
>NP_12345.1 matchnumber_1
RKHKK
>NP_56789.2 matchnumber_1
HGRR
>NP_56789.2 matchnumber_2
KQRHH
>NP_56789.2 matchnumber_3
RVRK
>NP_56789.2 matchnumber_4
HTHH
>XP_543421.1 matchnumber_1
RQRH
>XP_543421.1 matchnumber_2
RQRH
>XP_543421.1 matchnumber_3
RQRH

Пояснение:

($c1,@r)=split/\s+/,$_;             # split allline into 1 col value and rest of the line
for(@r){                            # for each lols othar than 1rst one
    ($c,$v)=$_=~/^(.+)_(.+)$/;      # extract before the last underscore and after it
    say "$c1 $c\n$v"                # print col1 coln linebreak value
}
0 голосов
/ 04 января 2019
$ cat jfile
>NP_12345.1     matchnumber_1_RKHKK
>NP_56789.2     matchnumber_1_HGRR      matchnumber_2_KQRHH     matchnumber_3_RVRK      matchnumber_4_HTHH

$ awk -F"\t" '{for(i=2;i<=NF;i++){match($i,"(matchnumber_[0-9]+)_(.*)",r);print $1 r[1] ORS r[2];}}' jfile
>NP_12345.1matchnumber_1
RKHKK
>NP_56789.2matchnumber_1
HGRR
>NP_56789.2matchnumber_2
KQRHH
>NP_56789.2matchnumber_3
RVRK
>NP_56789.2matchnumber_4
HTHH

Переходите от второго поля $2 к последнему полю $NF, используйте match и regex, чтобы вывести нужные объекты, например, matchnumber_1 и RKHKK для первого, и печатайте.

В пространстве awk только для конкатенации, ORS означает окончание строки, фактически равное \n здесь. r - это сопоставленный с регулярным выражением массив, где r [0] представляет всю совпавшую строку, r [1] и r [2] представляют первую и вторую пару () сопоставленного содержимого. - Вы можете изменить r на другое имя переменной, которое вы хотите.

Что касается регулярного выражения, [0-9] означает любое отдельное число, а + после этого означает совпадение с 1 или более обозначенными выше вещами, здесь означает 1 или более последовательных чисел. Как уже упоминалось выше, круглые скобки просто для того, чтобы перехватывать содержимое для групп, для дальнейшего использования. Каждая пара совпадений с круглыми скобками будет сохранена в один элемент предоставленного мною массива, который здесь равен r.

0 голосов
/ 04 января 2019

Perl на помощь!

$ cat james.txt
>NP_12345.1 matchnumber_1_RKHKK
>NP_56789.2 matchnumber_1_HGRR  matchnumber_2_KQRHH  matchnumber_3_RVRK matchnumber_4_HTHH
>XP_543421.1    matchnumber_1_RQRH matchnumber_2_QQQQ
$ perl -lne ' /(^\S+) (.+)/;$pre=$1;$mat=$2;while($mat=~/(match.+?_\d+)_(\S+)/g) { print "$pre $1\n$2" } ' james.txt
>NP_12345.1 matchnumber_1
RKHKK
>NP_56789.2 matchnumber_1
HGRR
>NP_56789.2 matchnumber_2
KQRHH
>NP_56789.2 matchnumber_3
RVRK
>NP_56789.2 matchnumber_4
HTHH
>XP_543421.1 matchnumber_1
RQRH
>XP_543421.1 matchnumber_2
QQQQ
$

Объяснение

perl -lne  
# -l to remove newline when reading and add newline when print statement is used
# -n - suppress default printing at the end of each line processing
# -e - for perl on commandline

' /(^\S+) (.+)/;
split line by first word (^\S+) -> matches first column and stores it in $1 since we used () to capture
the second (.+) stores the rest of the text in $2 

$pre=$1;$mat=$2; 

Assign $1 to $pre and $2 to $mat

while($mat=~/(match.+?_\d+)_(\S+)/g) 
Now mat stores from 2nd column to the rest of the line.
// => match with regex and (match.+?_\d+) to capture it in $1
(\S+) => captures the "HGRR"
/g => like this we have many matches.. so 'g'lobally repeat the matching 
to get all of them using the while loop. If /g is ignored, then we will just get first match alone.

 { print "$pre $1\n$2" } 
Now print $pre, $1 newline and $2 --> This $1 and $2 is local to the while loop and 
don't get confused with the earlier $1 and $2 which we assigned to $pre and $mat
for each while loop turn $1 and $2 match different values and get printed.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...