【问题标题】:Perl search and replace until positive lookahead over several lines - not working as expected?Perl 搜索和替换,直到多行的积极前瞻 - 没有按预期工作?
【发布时间】:2020-05-11 20:57:28
【问题描述】:

这里的总体目标是删除以特定字符串开头并以正向前瞻结尾的文本块。从我所做的测试来看,似乎换行符导致了问题,但我不确定到底发生了什么或修复它的最佳方法。

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

我认为这将是一个简单的任务,可以作为 bash (Ubuntu 18.04.2) 中的 perl 单行器来完成。 例如,从下面的摘录中,我想删除 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


    【解决方案1】:

    使用-p(或-n),一行代码一次读取一行;所以它不能匹配多行模式。一种解决方案是“啜饮”整个文件,如果它不是太大(逐行解决方案见末尾)

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

    见Command Switches in perlrun。

    然后,问题中显示的代码有一个不平衡的括号,并且无法编译。此外,没有理由捕获那些.s,所以去掉括号。接下来是图案

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

    匹配从第一个 > 到感兴趣的名称的所有内容,因此所有前面的序列也会被匹配和删除。相反,例如匹配>[^>]+...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
    

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

    第一个解决方案中的正则表达式必须对每个序列进行整体扫描,以发现它不是感兴趣的序列;只有当它到达下一个> 时,它才能确定序列不匹配(并且希望没有回溯,因为+? 会在遇到正确的短语时停止它)。

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

    因此,这里的工作量非常小——但这里的正则表达式引擎在每一行 行上启动,这很昂贵。如果不尝试,我无法确定它们是如何相互叠加的。

    【讨论】:

    • 有道理,非常感谢详细的逐个解释!
    • @ZeL 非常欢迎 :) 如果有更多问题,请告诉我
    • @ZeL 添加了逐行版本,当文件 太大而无法在内存中保存完整时。对于大文件,这也可能快得多。
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 2020-02-05
      • 1970-01-01
      • 2021-01-31
      相关资源
      最近更新 更多