Найти последовательные строки с определенными строками и изменить файл на основе таблицы

Найти последовательные строки с определенными строками и изменить файл на основе таблицы

У меня есть проблема с обработкой текста, которую я не смог решить. Допустим, у меня есть текстовый файл, как показано ниже (text.txt). Будут случаи, когда за строкой с /locus_tagследует строка с /gene, а будут и такие, когда ее нет. Я хочу найти все строки, в которых /locus_tagне следует за /gene, а затем использовать таблицу (table.txt), как показано ниже, чтобы сопоставить с /locus_tagи /geneдобавить ее /geneв мой текстовый файл после ее /locus_tag.

Любая идея, как это сделать, была бы замечательна.

/locus_tag="LOCUS_23770"
/note="ABC"
/locus_tag="LOCUS_23780"
/note="DEF"
/locus_tag="LOCUS_23980"
/note="GHI"
/locus_tag="LOCUS_24780"
/gene="BT_4758"
/note="ONP"
/locus_tag="LOCUS_25780"
/gene="BT_4768"
/note="WZX"

Стол

/locus_tag       /gene
LOCUS_00010      BT_4578
LOCUS_00020      BT_4577
LOCUS_00030      BT_2429

решение1

Используя ваши связанные файлы, это работает

awk 'BEGIN{FS="[ =]+"; OFS="="}
     BEGINFILE{fno++}
     fno==1{locus["\""$1"\""]="\""$2"\""; }
     fno>1{if (old ~ /LOCUS/ && $0 !~ /gene/) print "/gene", locus[old]; old=$3; print}
    ' table file1

До

                     /locus_tag="LOCUS_00030"
                     /note="WP_011108293.1 hypothetical protein (Bacteroides

После

                     /locus_tag="LOCUS_00030"
/gene="BT_2429"
                     /note="WP_011108293.1 hypothetical protein (Bacteroides

Поскольку вы не знакомы с awkпошаговым руководством

awk 'BEGIN{FS="[ =]+"; OFS="="}
# set up the input field separator as any group of spaces and/or =
# and set the output field separator as =

     BEGINFILE{fno++}
     # Whenever you open a file, increment the file counter fno

     fno==1{locus["\""$1"\""]="\""$2"\""; }
     # if this is the first file (i.e. table) load the array `locus[]`
     # but wrap the fields in "..." so that they are exactly like the data file entries

     fno>1{if (old ~ /LOCUS/ && $0 !~ /gene/) print "/gene", locus[old]; old=$3; print}
     # if this is a data file
     # if the current value of old (i.e. the previous line) is a LOCUS
     # and && this line ($0) isn't a gene
     # add a gene by indexing into the locus array based upon the value of old
     # because old contains the last LOCUS we found
     # in all cases
     #    set old to the 3rd field on the current line,
     #       which on any LOCUS line is the string "LOCUS_?????" and
     #    print the current line
     # See note below re $2 vs $3 and FS

    ' table file1
    # your input files, table must be first, you can have more data files if you want

Или без multichar FS, тогда сохраните, old=$2потому что он не разрывается на пробеле перед текстом в вашем файле данных, что делает multichar.

Ниже задается разделитель полей в зависимости от того, какой файл вы читаете FS=(fno==1)?" ":"=". Место для таблицы и =для данных

awk 'BEGIN{OFS="="}
     BEGINFILE{fno++;FS=(fno==1)?" ":"="}
     fno==1{locus["\""$1"\""]="\""$2"\""; }
     fno>1{if (old ~ /LOCUS/ && $0 !~ /gene/) print "/gene", locus[old]; old=$2; print}
    ' table file1

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

И поставьте тест, чтобы вставить сообщение в отсутствующие гены, если это подходит больше, чем просто пустые/gene=

fno>1{if (old ~ /LOCUS/ && $0 !~ /gene/) print "/gene", (old in locus)?locus[old]:"\"GENE_MISSING_AT_LOCUS\""; old=$3; print}

Измените ссылку на поле, чтобы oldона соответствовала FSиспользуемой вами версии.

                     /locus_tag="LOCUS_00020"
/gene="GENE_MISSING_AT_LOCUS"
                     /note="WP_008765457.1 hypothetical protein (Bacteroides

Редактировать

Если посмотреть на файл-образец, на который вы ссылаетесь, то проблема заключается в разнице в форматировании между образцом выше и вашими фактическими данными, что испортило номера полей. old=$2Нужно было просто изменить на old=$3. Исправлено выше.

Связанный контент