Perl readline问题

时间:2010-11-08 18:59:18

标签: perl readline

我要读一个文件,例如test.test包含

 #test:testdescription\n
 #cmd:binary\n
 #return:0\n
 #stdin:|\n
 echo"toto"\n
 echo"tata"\n
 #stdout:|\n
 toto\n
 tata\n
 #stderr:\n

我成功地取了#test:; #cmd:等... 但是对于stdinstdout,我想在下一个#之前将所有行放到表格@stdin@stdout

我做一个循环while ($line = <TEST>)所以它会查看每一行。如果我看到模式/^#stdin:|/,我想移动到下一行并将此值取为a 直到我看到下一个#

如何移至while循环中的下一行?

2 个答案:

答案 0 :(得分:2)

在为$/选择适当的值时,可以轻松处理这种文件格式:

use strict; use warnings;

my %parsed;

{
    local $/ = '#';
    while ( my $line = <DATA> ) {
        chomp $line;
        my $content = (split /:/, $line, 2)[1];
        next unless defined $content;
        $content =~ s/\n+\z//;
        if ( my ($chan) = $line =~ /^(std(?:err|in|out))/ ) {
            $content =~ s/^\|\n//;
            $parsed{$chan} = [ split /\n/, $content];
        }
        elsif ( my ($var) = $line =~ /^(cmd|return|test)/ ) {
            $parsed{ $var } = $content;
        }
    }
}

use YAML;
print Dump \%parsed;

__DATA__
#test:testdescription
#cmd:binary
#return:0
#stdin:|
echo"toto"
echo"tata"
#stdout:|
toto
tata
#stderr:

输出:

---
cmd: binary
return: 0
stderr: []
stdin:
  - echo"toto"
  - echo"tata"
stdout:
  - toto
  - tata
test: testdescription

答案 1 :(得分:1)

根据用户的colmments更新

如果我正确理解了这个问题,你想在循环中再读一行吗?

如果是这样,您可以:

  1. 只需在循环中读取另一行。

    my $another_line = <TEST>;
    
  2. 保留一些状态标志并在循环的下一次迭代中使用它,并在缓冲区中的stdins之间累积行:

    my $last_line_was_stdin = 0;
    my @line_buffer = ();
    while ($line = <TEST>) {
        if (/^#stdin:|/) {
            #
            # Some Code to process all lines acccumulated since last "stdin"
            #
            @line_buffer = ();
            $last_line_was_stdin = 1;
            next;
        }
        push @line_buffer, $line;
    }
    

    此解决方案可能无法满足您的需求,但它定义了您在状态机实现中需要遵循的模式:读取一行。检查您当前的状态(如果重要)。根据当前状态和行中的模式,验证当前行做什么(添加到缓冲区?更改状态?如果更改状态,根据上一个状态处理缓冲区?)

  3. 另外,根据你的评论,你的正则表达式中有一个错误 - 管道(|字符)在正则表达式中意味着“或”,所以你说“如果行以#stdin开头”或者匹配一个空的正则表达式“ - 后一部分总是正确的,所以你的正则表达式将匹配100%的时间。你需要逃避“|”通过/^#stdin:\|//^#stdin:[|]/