Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How to push the previous line based on the current line to two different files.

by suno (Acolyte)
on Sep 13, 2012 at 05:34 UTC ( [id://993366]=perlquestion: print w/replies, xml ) Need Help??

suno has asked for the wisdom of the Perl Monks concerning the following question:

say my current line is $Line [foreach $Line (@Read_Array)]... say my code is as follows:
LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * + $NOT UPDATE,STOP T#TAB1 EQU * + DC AL4(-1)
Here, anything followed by "EQU *" is said to be a label/table name. I have to generate two output files 1)Code and 2)Variable files ...here, i want to identify whether the label belongs to code file or variable file. if a label followed by DC statements, then it has to be pushed to variable file. else to code file. so my output files shoul have...

CODE_FILE:

LABEL#1 EQU * + $MAC ABORT + LABEL#2 EQU * + $NOT UPDATE,STOP

VARIABLE_FILE:

T#TAB1 EQU * + DC AL4(-1)

please help me in this without using while loop...

Replies are listed 'Best First'.
Re: How to push the previous line based on the current line to two different files.
by aaron_baugher (Curate) on Sep 13, 2012 at 07:14 UTC

    Forbidding the use of a while loop seems like an odd homework requirement, since a while loop is the idiomatic way to read data in Perl. But you're welcome to use this 100% while-free solution:

    UPDATE: I see that the requirements changed, and records can no longer be assumed to be divided by a blank line. But the point remains: rather than reading line-by-line and trying to succeeding lines based on previous ones, it's often much easier to read block-by-block, if it's possible to find a way to set the input record separator to do so.

    #!/usr/bin/env perl use Modern::Perl; open my $labels, '>', 'labels.txt'; open my $tables, '>', 'tables.txt'; { $/ = ''; START: my $record = <DATA>; exit unless $record; my $fd = $record =~ /\*\s+DC/s ? $tables : $labels; print $fd $record; goto START; } __DATA__ LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * + $NOT UPDATE,STOP T#TAB1 EQU * + DC AL4(-1)

    Aaron B.
    Available for small or large Perl jobs; see my home node.

Re: How to push the previous line based on the current line to two different files.
by davido (Cardinal) on Sep 13, 2012 at 06:26 UTC

    Untested, but it should get you going in the right direction.

    open my $code_fh, '>', 'codefile.txt' or die $!; open my $var_fh, '>', 'varfile.txt' or die $!; open my $in_fh, '<', 'infile.txt' or die $!; local $/ = "\n\n"; while ( <$in_fh> ) { print { m/^\s+DC\s+/m ? $var_fh : $code_fh } $_; } close $var_fh or die $!; close $code_fh or die $!;

    Dave

Re: How to push the previous line based on the current line to two different files.
by kcott (Archbishop) on Sep 13, 2012 at 06:27 UTC

    G'day suno,

    This does what you want based on your input. I'll leave you to supply appropriate filehandles for the output.

    #!/usr/bin/env perl use 5.010; use strict; use warnings; my @Read_Array = <DATA>; my (@code_file, @var_file); my $var_file_re = qr{ \A \s* DC }x; my $label_re = qr{ \s+ EQU \s+ \* }x; my $label_line = ''; for (@Read_Array) { if (/$label_re/) { $label_line = $_; next; } if ($label_line) { $label_line .= $_; if (/$var_file_re/) { push @var_file, $label_line; } else { push @code_file, $label_line; } $label_line = ''; } } say 'CODE_FILE:'; print join "\n" => @code_file; say 'VARIABLE_FILE:'; print join "\n" => @var_file; __DATA__ LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * + $NOT UPDATE,STOP T#TAB1 EQU * + DC AL4(-1)

    Output:

    $ pm_capture_last.pl CODE_FILE: LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * + $NOT UPDATE,STOP VARIABLE_FILE: T#TAB1 EQU * + DC AL4(-1)

    -- Ken

      Avoid needless slurping. Use while (<DATA>) instead of introducing an extra variable, slurping into it and using a for loop.

      Slurping complicates the code (there are more moving parts), it doesn't scale well, it obscures the intent of the code because it decouples line reading from line processing, and it probably doesn't offer any useful efficiency gains (which shouldn't be a consideration in the first place).

      You code could be "cleaned up" as:

      #!/usr/bin/env perl use strict; use warnings; my @code_file; my @var_file; my $label_line; while (<DATA>) { if (/\s+EQU\s+\*/) { $label_line = $_; next; } next if ! $label_line; push @{/\A\s*DC/ ? \@var_file : \@code_file}, "$label_line$_"; $label_line = ''; } print join "\n", "CODE_FILE:", @code_file, "VARIABLE_FILE:", @var_file +; __DATA__ LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * $NOT UPDATE,STOP T#TAB1 EQU * DC AL4(-1)
      True laziness is hard work
        "Avoid needless slurping. Use while (<DATA>) instead of introducing an extra variable, slurping into it and using a for loop."

        The OP (suno) is using a for loop to read through data in the @Read_Array array - that's a variable suno already has, not an extra variable.

        No indication is given of how that array is populated.

        my @Read_Array = <DATA>; (in my code) initialises @Read_Array with the data shown.

        suno's question is not about how to capture the data; it's about how to process it once it's in @Read_Array.

        Finally, suno specifically says "... without using while loop ...". I don't know why that is requirement: perhaps addressing your data capture comments to suno would be more appropriate.

        -- Ken

      Hi ,

      Thanks for the help. But here in this i am able to print only the line immediate after 'EQU *'...

      I wish to pring evrything after EQU *..

      say suppose my input is

      LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * $NOT UPDATE,STOP T#TAB1 EQU * DC AL4(-1) L#DESK DC XL6 DESKRIPTOR L#SYMBOL DC CL30 SYMBOL L#TKKEY DC XL4 VALOREN-NUMMER FNK#005 EQU * CLI V#MUT,X'FF' WURDE MUTIERT ? BNE F05#000 NEIN MVI FUNK,4 MDF-TG ERZEUGEN $CALL MOD850,UP F$SFH TR_COMMIT
      here according the above perl code u gave me, the output i aquire is:
      CODE_FILE: LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * $NOT UPDATE,STOP FNK#005 EQU * CLI V#MUT,X'FF' WURDE MUTIERT ? VARIABLE_FILE: T#TAB1 EQU * DC AL4(-1)

      where i wish to get...

      CODE_FILE: LABEL#1 EQU * $MAC ABORT LABEL#2 EQU * $NOT UPDATE,STOP FNK#005 EQU * CLI V#MUT,X'FF' WURDE MUTIERT ? BNE F05#000 NEIN MVI FUNK,4 MDF-TG ERZEUGEN $CALL MOD850,UP F$SFH TR_COMMIT B F05#100 VARIABLE_FILE: T#TAB1 EQU * DC AL4(-1) L#DESK DC XL6 DESKRIPTOR L#SYMBOL DC CL30 SYMBOL L#TKKEY DC XL4 VALOREN-NUMMER

      What change shall i make in the above perl code so as to get this output?

        What change shall i make in the above perl code so as to get this output?

        Do you have any guess?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://993366]
Approved by chacham
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2024-03-19 05:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found