Perl поиск и замена до положительного взгляда на несколько строк - не работает, как ожидалось? - PullRequest
1 голос
/ 26 января 2020

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

Больше контекста: я хочу удалить таксоны из файла .fasta, включая название таксона и информацию заголовка и связанную последовательность. (формат fasta начинается с заголовка> locusname-locusnumber-видов_имя | locusname-locusnumber \ n). Недостающие данные в последовательности кодируются как "-". В конце концов, я хотел бы сделать это для нескольких видов_имений и сделать это для каждого из нескольких тысяч файлов в каталоге.

Я предполагал, что это будет простая задача для однострочного perl в bash (Ubuntu 18.04.2). В качестве примера, из приведенной ниже выдержки я хотел бы удалить всю последовательность Pseudomymrex seminole D1367, то есть строку, начинающуюся с > uce-483_Pseudomyrmex_seminole_D1367 | uce-483 и заканчивающуюся новой строкой перед > UCE-483_Pseudomyrmex_seminole_D1435. , . .

Для этого у меня есть: perl -pe 's/>(.)+(Pseudomyrmex_seminole_D1367)[\s\S]+(?=>)//' infile.fasta > outfile.fasta

или эквивалентно perl -pe 's/>(.)+(Pseudomyrmex_seminole_D1367(.)+(?=>)//s' infile.fasta > outfile.fasta

Оба из них, кажется, не имеют никакого эффекта вообще (то есть diff infile.fasta outfile.fasta пусто.) Если я уберу положительный прогноз, он будет работать правильно, но только до первой новой строки.

Вот выдержка из .fasta для контекста и тестирования:

>uce-483_Pseudomyrmex_seminole_D1366 |uce-483
------------------------------------------------------------
---------------------------------------------------tgtaaacgt
tataatacatgcgtatgaaaaaaaaaagtgaacacccggtacgtacccgtgctgaaacgt
tcagatttacatccatttgtagtagcattttcgctagttttttcaagagcaaaaaggaca
cattcaaaactgaatatacatgtcacagatgtttgtttgtgtgcaggtacctgtaatttt
gcaaacatatacctatatatgtgtgtcgcatatatatcatgtagtagatttccatgttat
gcaacatcttctcacaatgacaatcggtcgtttccttcactccgaaatgttcatgcgaac
agttaatctatatcccaagcagcgatgtaatgttatgcggcgcgcaagtctcattagact
tgtaaaccgtccgagtttcgacttaccata----tgtgtgtgtgtgcgcgcgtatgtgca
cgtac------acacgtttgtttatacatttgtctatacatttgcgtgtgaacgcgggat
gaacagagatttgcgcacacatagacatgagaaacgtcacttgtcgatgtagatactaat
tgtggaaaatacatattcctcttcagatacacgggaatgttgaattattttcactcgctc
cacgcgcgagtgttcgctccttttacgcacaacgagtccttctgctgcagc--gagatag
aaaatatttttgcgcggtaatcgtaaacgtatgagtgcctttcgacgtgaattctcttat
ggcagttctcacggtgtaaattataatcgaattaacattgcgagtgtgatctcaatataa
ttatagcgtctaagaacaaacacgtaacatgcacacacacacacacacac----------
---
>uce-483_Pseudomyrmex_seminole_D1367 |uce-483
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
--ttcaaaactgaatatacatgtcacagatgtttgtttgtgtgcaggtacctgtaatttt
gcaaacatatg---atatatatgtgtcgcatatatatcatgtagtagatttccatgttat
gcaacatcttctcacaatgacaatcggtcgtttccttcactctgaaatgttcatgcgaac
agttaatctatatcccaagcagcgatgtaatgttatgcggcgcgcaagtctcattagact
tgtaaaccgtccgagtttcgacttaccata--tgtgtgtgtgtgtgtgcgcgtatgtgca
cgtacgcgcgcacacgtttgtttatacatttgtctatacatttgcgtgtgaacgcgggat
gaacagagatttgcgcacacatagacatgagaaacgtcacttgtcgatg-----------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
---
>uce-483_Pseudomyrmex_seminole_D1435 |uce-483
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
-------tacatccatttgtagtagcattttcgctagttttttcaagagcaaaaaggaca
cattcaaaactgaatatacatgtcacagatgtttgtttgtgtgcaggtacctgtaatttt
gcaaacatatacctatatatgtgtgtcgcatatatatcatgtagtagatttccatgttat
gcaacatcttctcacaatgacaatcggtcgtttccttcactccgaaatgttcatgcgaac
agttaatctatatcccaagcagcgatgtaatgttatgcggcgcgcaagtctcattagact
tgtaaaccgtccgagtttcgacttaccata--tgtgtgtgtgtgtgtgcgcgtatgtgca
cgtac------acacgtttgtttatacatttgtctatacatttgcgtgtgaacgcgggat
gaacagagatttgcgcacacatagacatgagaaacgtcacttgtcgatgtagatactaat
tgtggaaaatacatattcctcttcagatacacgggaa-----------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
---

Ответы [ 2 ]

3 голосов
/ 26 января 2020

С -p (или -n) однострочник читает строку одновременно; поэтому он просто не может соответствовать многострочным шаблонам. Одно из решений заключается в том, чтобы «налить» весь файл, если он не слишком большой ( см. Конец для построчного решения )

perl -0777 -pe'...' in > out   

См. Команду Включает perlrun .

Затем код, показанный в вопросе, содержит несбалансированные скобки и не компилируется. Кроме того, нет причин фиксировать эти . s, поэтому снимите круглые скобки. Затем шаблон

s/>.+Pseudomyrmex_seminole_D1367...//;

сопоставляет все, начиная с самого первого > и заканчивая именем, представляющим интерес, поэтому все предыдущие последовательности также сопоставляются и удаляются. Вместо этого сопоставьте, например, >[^>]+...D1367, чтобы все, что не > после >, соответствовало этой фразе.

Наконец, последний .+(?=>) будет сопоставлять все с очень last > и, таким образом, регулярное выражение удалит все последующие последовательности, а не то, что вы хотите в соответствии с описанием. Вместо этого ограничьте его до первого следующего >, либо сделав его «нежадным» с .+?(?=>) или, проще, с [^>]+.

Все исправлено

perl -0777 -pe's/>[^>]+?Pseudomyrmex_seminole_D1367[^>]+//' in > out

Обратите внимание, что модификатор /s теперь не нужен, поскольку его цель - заставить . соответствовать символу новой строки, и здесь нам это не нужно, поскольку [^>] также соответствует символу новой строки (что-нибудь другое чем >). Квантификатор +? предназначен для (надеюсь) предотвращения обратного отслеживания каждой целой последовательности, которая не соответствует.

Или с вашим первоначальным использованием lookahead

perl -0777 -pe's/>[^>]+?Pseudomyrmex_seminole_D1367.+?(?=>)//s' in > out

Они работают так, как ожидается с вашим образец, а также расширенный пример, который я составил с добавлением дополнительных последовательностей (>...).


Для справки, и поскольку файл fasta может быть слишком большим, чтобы его можно было перетянуть в строку, здесь это строка за строкой.

Как только вы увидите интересующую линию >..., установите флаг; выведите строку, если этот флаг не установлен (и если мы не на этой строке). Как только вы доберетесь до следующего >, снимите флажок (напечатайте и эту строку).

perl -ne'
    if (/^>.+?Pseudomyrmex_seminole_D1367/) { $f = 1 } 
    elsif (not $f) { print } 
    elsif (/^>/) { $f = 0; print }
' in > out

Я подозреваю, что это также может работать значительно лучше для очень больших файлов.

Регулярное выражение в первом решении нужно просканировать каждую последовательность целиком, чтобы найти, что она не представляет интерес; только после того, как он достигнет следующего >, он может решить, что последовательность не совпадает (и, надеюсь, без обратного отслеживания, поскольку +? остановил бы его, если бы была найдена правильная фраза).

Здесь код в основном проверяет первый символ и флаг.

Так что здесь несравнимо меньшая рабочая нагрузка - но здесь механизм регулярных выражений запускается на каждой строке, и это дорого. Я не могу с уверенностью сказать, как они складываются друг против друга, не пытаясь.

1 голос
/ 26 января 2020

Вы также можете использовать > в качестве разделителя входных записей. Таким образом, вы избегаете создавать весь файл, и поскольку основной l oop загружает ваш файл блок за блоком, вам нужно только проверить, какой из них является целевым, чтобы не печатать его (без описания всего блока в шаблоне):

perl -ln076e's/\n$//;print ">$_" if $_ && !/Pseudomyrmex_seminole_D1367/' file

Переключатель l устанавливает разделитель выходной записи на разделитель входной записи (по умолчанию - новую строку).
Переключатель 0 устанавливает разделитель входной записи на > (76 в восьмеричном).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...