我要读一个文件,例如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:等...
但是对于stdin
或stdout
,我想在下一个#
之前将所有行放到表格@stdin
和@stdout
。
我做一个循环while ($line = <TEST>)
所以它会查看每一行。如果我看到模式/^#stdin:|/
,我想移动到下一行并将此值取为a
直到我看到下一个#
。
如何移至while
循环中的下一行?
答案 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更新
如果我正确理解了这个问题,你想在循环中再读一行吗?
如果是这样,您可以:
只需在循环中读取另一行。
my $another_line = <TEST>;
保留一些状态标志并在循环的下一次迭代中使用它,并在缓冲区中的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;
}
此解决方案可能无法满足您的需求,但它定义了您在状态机实现中需要遵循的模式:读取一行。检查您当前的状态(如果重要)。根据当前状态和行中的模式,验证当前行做什么(添加到缓冲区?更改状态?如果更改状态,根据上一个状态处理缓冲区?)
另外,根据你的评论,你的正则表达式中有一个错误 - 管道(|
字符)在正则表达式中意味着“或”,所以你说“如果行以#stdin
开头”或者匹配一个空的正则表达式“ - 后一部分总是正确的,所以你的正则表达式将匹配100%的时间。你需要逃避“|”通过/^#stdin:\|/
或/^#stdin:[|]/