Dung
Dung

Reputation: 81

Perl readline problem

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?

Upvotes: 1

Views: 513

Answers (2)

DVK
DVK

Reputation: 129403

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:[|]/

Upvotes: 1

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

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

Upvotes: 2

Related Questions