【问题标题】:How can I keep only the first five lines in a Perl scalar?如何在 Perl 标量中只保留前五行?
【发布时间】:2009-04-22 10:31:23
【问题描述】:

对于任何一种标量,我可以使用什么正则表达式来匹配它的前五行并丢弃其余行?

【问题讨论】:

    标签: regex perl lines scalar


    【解决方案1】:

    奇怪的请求,但应该这样做:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $s = join '', map { "$_\n" } 1 .. 9;
    
    my ($first) = $s =~ /^((?:.*\n){0,5})/;
    my ($last) = $s =~ /((?:.*\n){0,5})$/;
    
    
    print "first:\n${first}last:\n$last";
    

    一个更常见的解决方案是这样的:

    #!/usr/bn/perl
    
    use strict;
    use warnings;
    
    #fake a file for the example    
    my $s = join '', map { "$_\n" } 1 .. 9;    
    open my $fh, "<", \$s
        or die "could not open in memory file: $!";
    
    my @first;
    while (my $line = <$fh>) {
        push @first, $line;
        last if $. == 5;
    }
    
    #rewind the file just in case the file has fewer than 10 lines
    seek $fh, 0, 0;
    
    my @last;
    while (my $line = <$fh>) {
        push @last, $line;
        #remove the earliest line if we have to many
        shift @last if @last == 6;
    }
    
    print "first:\n", @first, "last:\n", @last;
    

    【讨论】:

    • 如何将它应用到最后 5 行?
    • 我的 ($last_five_lines) = $s =~ /((?:.*\n){5})\z/;
    • 你需要一个 {0,5} 修饰符,否则它将拒绝一个 4 行字符串(除非这是你想要的)。
    【解决方案2】:

    你为什么不直接使用head呢?

    【讨论】:

    • 如果您的大字符串在 Perl 程序中并且您不想创建临时文件,则不能这样做。
    • @brian d foy 嗯,不对,你可以打开一个双向管道到头;这很愚蠢,但你可以做到。
    • 您确定可以打开双向管道吗? Perl 在很多地方都可以运行,你知道的。 :)
    【解决方案3】:

    您不需要正则表达式。只需打开对标量的引用的文件句柄,然后执行与任何其他类型的文件句柄相同的操作:

    my $scalar = ...;
    
    open my($fh), "<", \ $scalar or die "Could not open filehandle: $!";
    foreach ( 1 .. 5 )
        {
        push @lines, scalar <$fh>;
        }
    close $fh;
    
    $scalar = join '', @lines;
    

    【讨论】:

    • Brian - 这是你在 open() 调用中两次引用 $fh 的错字吗?
    【解决方案4】:
    my ($first_five) = $s =~ /\A((?:.*\n){5})/;
    my ($last_five) = $s =~ /((?:.*\n){5})\z/;
    

    【讨论】:

      【解决方案5】:

      正如 Brian 所说,您可以很容易地使用 headtail 来解决任一问题(前 5 行或后 5 行)。

      但现在我想知道我是否正确理解了您的问题。当您说“对于任何类型的标量”时,您的意思是(无论出于何种原因)文件已经是标量吗?

      如果不是,我认为最好的解决方案是根本没有正则表达式。使用$. 并正常或向后读取文件。要向后阅读,您可以尝试File::ReadBackwardsFile::Bidirectional

      【讨论】:

      • File::ReadBackwards 如果文件很长很好。
      【解决方案6】:

      人们缺少一些关键标志:

      /(?m)((?:^.*\n?){1,5})/
      

      没有多行标志,它只会查看第一行。此外,通过将\n 设为可选,我们可以使用前五行,而不管第五行末尾是否有换行符。

      【讨论】:

        【解决方案7】:

        为什么不直接使用带限制的拆分,它就是为此目的而设计的:

        my @lines = (split /\n/, $scalar, 6)[0..4];
        

        如果您希望将其作为一个包含五行的单个标量,请将其连接起来:

        my $scalar = join('\n', @lines) . "\n";
        

        【讨论】:

          【解决方案8】:
          use strict;
          
          
          my $line; #Store line currently being read
          my $count=$ARGV[1]; # How many lines to read as passed from command line
          my @last; #Array to store last count lines
          my $index; #Index of the line being stored
          
          
          #Open the file to read as supplied from command line
          open (FILE,$ARGV[0]);
          while ($line=<FILE>)
          {
              $index=$.%$count;  # would help me in filter just $count records of the file
              $last[$index]=$line; #store this value
          }
          close (FILE);
          
          #Output the stored lines
          for (my $i=$index+1;$i<$count;$i++)
          {
              print ("$last[$i]");
          }
          for (my $i=$0;$i<=$index;$i++)
          {
              print ("$last[$i]");
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-04
            • 2012-01-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-10-12
            • 2017-06-28
            相关资源
            最近更新 更多