Perl搜索并替换,直到对多行进行正向查找-不能按预期工作?

问题描述 投票:1回答:2

这里的总体目标是删除以特定字符串开头并以正向超前结尾的文本块。从我完成的测试来看,换行符似乎是导致此问题的原因,但我不确定到底是怎么回事或解决此问题的最佳方法。

[更多上下文:我想从.fasta文件中删除分类单元,包括分类单元名称和标头信息以及相关的序列。 (fasta格式以头> locusname-locusnumber-species_name | locusname-locusnumber \ n开头)。序列中丢失的数据被编码为“-”。最终,我想对几个种类名称进行此操作,并对目录中的数千个文件都进行此操作。

我想这是在bash中作为perl单线执行的一项简单任务(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-----------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
---
regex perl replace regex-lookarounds fasta
2个回答
2
投票

[使用-p(或-n)时,单线一次读取一行;因此它不能匹配多行模式。一种解决方案是将整个文件“混入”(如果文件太大)(请参阅逐行解决方案的末尾

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

请参见Command Switches in perlrun

然后,问题中显示的代码带有不平衡的括号,并且无法编译。此外,没有理由捕获那些.,因此在括号中放下括号。接下来,模式

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

匹配从very first >到感兴趣名称的所有内容,因此第一个序列也是如此。相反,例如,将>[^>]+...D1367匹配,以便将>之后不是>的所有内容都匹配到该短语。

最后,最后一个.+(?=>)将使所有内容与非常最后 >匹配,因此正则表达式将删除所有后续序列,而不是根据描述所需要的序列。相反,可以通过将其与>或更简单地与.+?(?=>)设为“非贪婪”,将其限制为与后一个[^>]+匹配。

所有已更正

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

[请注意,现在不需要/s修饰符,因为它的目的是使.匹配换行符,而在这里我们不需要-也是[^>]也匹配换行符(其他比>)。

或者,使用您的超前使用方式

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

我怀疑这在很大的文件上也可能表现得更好。

第一个解决方案中的正则表达式必须扫描每个序列整体,以发现它是目标序列。只有击中下一个>时,它才能确定序列不匹配(有一些额外的回溯)。

这里的代码主要检查第一个字符和一个标志。

因此,这里的工作量无可比拟地减少了-但是这里的regex引擎是在

every]行上启动的,这很昂贵。我只是无法不经过尝试就告诉他们如何相互堆叠。

您也可以使用>作为输入记录分隔符。这样,您就避免了对整个文件进行处理,并且由于主循环逐块加载文件,因此您只需测试哪个目标是不打印文件(无需以模式描述整个块):

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

l开关将输出记录分隔符设置为输入记录分隔符(默认为换行符)。0开关将输入记录分隔符设置为>(八进制76)。

1
投票
您也可以使用>作为输入记录分隔符。这样,您就避免了对整个文件进行处理,并且由于主循环逐块加载文件,因此您只需测试哪个目标是不打印文件(无需以模式描述整个块):

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

© www.soinside.com 2019 - 2024. All rights reserved.