Perl 读取行问题

发布于 2024-10-01 09:02:39 字数 539 浏览 0 评论 0原文

我要读取一个文件,例如 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 =) 所以它会查看每一行。如果我看到一个模式 /^#stdin:|/,我想移动到下一行并将该值设置为 表直到我看到下一个#

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

I'd to read a file, e.g. test.test which contains

 #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

I succeeded in taking which are after #test: ; #cmd: etc...
but for stdin or stdout, I want to take all the line before the next # to a table @stdin and @stdout.

I do a loop while ($line = <TEST>) so it will look at each line. If i see a pattern /^#stdin:|/, I want to move to the next line and take this value to a
table until i see the next #.

How do I move to the next line in the while loop?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谜兔 2024-10-08 09:02:39

通过为 $ 选择适当的值,可以轻松处理此文件格式。 /

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

This file format can be easily handled with some creativity in selecting the appropriate value for $/:

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:

Output:

---
cmd: binary
return: 0
stderr: []
stdin:
  - echo"toto"
  - echo"tata"
stdout:
  - toto
  - tata
test: testdescription
乖乖兔^ω^ 2024-10-08 09:02:39

根据用户的评论进行更新

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

如果是这样,您可以:

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

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

    我的 $last_line_was_stdin = 0;
    我的@line_buffer = ();
    while ($line = <测试>) {
        如果 (/^#stdin:|/) {
            #
            # 一些代码来处理自上次“stdin”以来累积的所有行
            #
            @line_buffer = ();
            $last_line_was_stdin = 1;
            下一个;
        }
        推@line_buffer,$line;
    }
    

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

另外,根据您的评论,你的正则表达式中有一个错误 - 管道(|字符)在正则表达式中意味着“OR”,所以你说“如果行以#stdin开头或匹配空正则表达式” - 后一部分始终为真,因此您的正则表达式将 100% 匹配。您需要转义“|”通过 /^#stdin:\|//^#stdin:[|]/

UPDATED as per user's colmments

If I understand the question correctly, you want to read one more line within a loop?

If so, you can either:

  1. just do another line read inside the loop.

    my $another_line = <TEST>;
    
  2. Keep some state flag and use it next iteration of the loop, and accumulate lines between stdins in a buffer:

    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;
    }
    

    This solution may not do 100% of what you need but it defines a pattern you need to follow in your state machine implementation: read a line. Check your current state (if it matters). Based on the current state and a pattern in the line, verify what do do about the current line (add to the buffer? change the state? If changing a state, process the buffer based on last state?)

Also, as per your comment, you have a bug in your regex - the pipe (| character) means "OR" in regex, so you are saying "if line starts with #stdin OR matches an empty regex" - the latter part is always true so your regex will match 100% of time. You need to escape the "|" via /^#stdin:\|/ or /^#stdin:[|]/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文