处理单独的回车符作为行尾符号

时间:2010-12-18 07:39:22

标签: perl carriage-return

所以我有一个程序可以摆脱fasta文件中的额外换行符复制并从网上粘贴。如果你不知道一个fasta文件应该是什么样子,它应该是一个大于符号后跟任何东西(这通常是标题信息),然后是新行。新品系应在一行中包含您的完整序列(对于生物学DNA或氨基酸),并重复。

无论如何,问题是我需要程序足够灵活以处理任何事情:\r\n\r\n。带有下划线的chomp语句是删除序列部分中多余行的命令。如何让这个选择摆脱所有三个选项(\r\n\r\n)?我可以设置$\ = @linefeeds并拥有@linefeeds = "\r", "\n", "\r\n";吗?

我已经在线阅读了,我知道之前已经讨论过这个话题,但我似乎无法让它发挥作用。

以下是我在文件中执行此操作的代码:

print "Please enter file name, using the full pathway, to save your cleaned fasta file to:\n";
chomp( $new_file = <STDIN> );
open( New_File, "+>$new_file" ) or die "Couldn't create file. Check permissions on location.\n";

#process the file line by line, chomping all lines that do not contain "greater than" and
#removing all white space from lines that do not contain "greater than"

my $firstline = 1;
while ( my $lines = <FASTA> ) {
    foreach ($lines) {
        if ( !/>/ ) {
            _chomp($lines);_
            $lines =~ s/ //g;
            print New_File "$lines";
        } else {
            if ( $firstline == 1 ) {
                print New_File "$lines";
                $firstline = 0;
            } else {
                print New_File "\n$lines";
                next;
            }
        }
    }
}

3 个答案:

答案 0 :(得分:3)

根本问题是$/只能设置为单个字符串,并且没有值可以将其设置为匹配所有CR,LF和CRLF行结尾。< / p>

但是,你不是第一个遇到这个问题的人。我自己没有尝试过,但是如果你安装了PerlIO::eol,你应该可以说:

binmode FASTA, ":raw:eol(LF)";

它会自动将CR,LF或CRLF行结尾转换为LF。

答案 1 :(得分:2)

我倾向于使用s/[\r\n]+$//;。当我还想删除尾随空格时,我实际使用s/[\s\r\n]+$//;

从Perl手册中,只需s/\s+$//;就可以说\s同时包含\r\n,但我喜欢拼写它的清晰度。

答案 2 :(得分:2)

您的问题有三个问题需要解决:

  • 如何剥离空白的技术问题包括字符串中的各种换行符

  • 如何处理所述文件格式的一般问题。我将提出一个不同的解决方案,如果文件大小足够小,你可以将整个文件粘贴到内存中的字符串中。

  • 以块的形式读取文件(例如逐行),以避免将整个文件丢入内存。


  1. 要从非标题行中删除空白和各种换行(例如您的_chomp_)行,您可以执行以下操作:

    $lines =~ s/[\n\r]|\s//gs; # IIRC, \s doesn't include newlines
    
  2. 此外,如果您的文件足够小以至于将其作为单个长字符串插入内存中是一个选项,您可以(代价稍慢的代码),有一个更短的,希望更可读的逻辑,而不是示例代码中的逻辑:

    my @lines = split(/(\015|\012|\015\012)>/, $text); # Split on ">" first line char
    foreach my $line (@lines) {
        my ($title, $rest) = ($line =~ /^(>[^\n\r]+)[\n\r](.*)$/s);
        $rest =~ s/[\n\r]|\s//gs; # Strip whitespace AND newlines.
        print New_File "$title\n$rest\n";
    }
    
  3. 但是,如果数据足够大,你必须以块的形式读取它(如果是文本,那么块通常是一行),你有问题,同时你的建议的代码和我上面展示的代码。

    通过<>运算符(或readline)的Perl标准逐行读取将使用输入记录分隔符($/)来定义换行符, 默认为“\ n”。如果你的文件全部被“\ r”分开,它将被视为一个巨大的单行, 这意味着你无论你喜不喜欢都会诋毁文件。显然,将$/更改为“\ r”将无济于事。

    不幸的是,$/(输入记录分隔符)必须是字符串,不能是正则表达式。

    因此,如果由于尺寸考虑,绝对必须以块的任意换行读取文件, 您需要以固定块大小而不是逐行读取文件,然后从这些块中解析出各行。

    要进行此类阅读,IIRC,您可以将$/设置为整数,然后使用readline() / <>

    请注意cjm的答案(PerlIO :: eol)提到的模块完全采用后一种方法, 但它是作为XS模块实现的,因此用C代码实现(PerlIOEOL_get_base()函数的缓冲区大小为4k)。