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

Hi I am confuse as to why the following codes does not work:
#!/usr/perl/bin use strict; my @words; my @array; my $i = 0; open RI,"<C:\\test.txt" || die "Can't open test.txt for reading: $!\n" +; open (LOG,">C:\\lp.txt") || die "can't open logfile: $!\n"; while(<RI>) { if (/^printer/) { my @strings = (split)[1,3,4]; if ( $strings[1] eq "idle." ) { push @array, [ "0", 6 ]; } if ( $strings[2] eq "enabled" ) { my $s = "Up"; push @array, [ $s, 5 ]; } push @array, [ $strings[0], 1 ]; } elsif (m|Interface:(.+)|i) { @words = split(/\//, $_); chomp($words[-1]); push @array, [ $words[-1], 3]; } elsif (m|Description: (.+)|i) { push @array, [ $1, 4]; } elsif (m|Connection: (.+)|i) { if ($1 eq "direct" ) { push @array, [ "local", 8]; } else { push @array, [ "remote", 8]; } } elsif (/Banner not required/) { push @array, ["No",7 ]; } if ($i == 3) { for ( sort { $a->[1] <=> $b->[1] } @array ) { print "$_->[0]|"; } @array=(); $i =0; } else { $i++; } }
Here 's the data from the file I am reading in:
rinter llp is idle. enabled since Wed Oct 23 15:54:08 GMT 2002. availa +ble. Form mounted: Content types: any Printer types: unknown Description: OPENprint printer llp Connection: direct Interface: /usr/lib/lp/model/standard On fault: write to root once After fault: continue Users allowed: (all) Forms allowed: (none) Banner not required Character sets: (none) Default pitch: Default page size: Default port settings: -opost printer ps is idle. enabled since Wed Oct 23 15:54:17 GMT 2002. availa +ble. Form mounted: Content types: postscript, simple Printer types: unknown Description: local printer Connection: direct Interface: /usr/lib/lp/model/net_lj4x On fault: write to root once After fault: continue Users allowed: (all) Forms allowed: (none) Banner not required Character sets: (none) Default pitch: Default page size: Default port settings:
The result I am getting: llp|Up|0|local|standard|OPENprint printer llp|No|ps|Up|0|local|net_lj4x|local printer|No| The result I want: llp|local|Standard|OPENprint printer llp|Up|0|No| ps|local|net_lj4x|local printer|Up|0|No| why is the string "Up" and "0" appearing in the second and third position and not fifth and sixth. Thanks for all inputs. --kirk

Replies are listed 'Best First'.
Re: Array insertion problem
by sauoq (Abbot) on Dec 11, 2002 at 01:36 UTC

    I think it is breaking because you are printing every time you read in three lines, not every time you get three lines that you actually parse.

    In the first three lines, you only parse the first one. At that point your array contains three pieces of information, ( ["llp", 1], ["Up", 5], [0, 6] ), the first time you print. It sorts them properly; you just don't have all the data yet. I suspect you are missing an else { next } in that block of elsifs.

    That said, I feel compelled to tell you that your code is horrid. If I knew how to say it nicely, I would. If I was expected to maintain that, I would not hesitate to write it over again from scratch, all the while cursing your name. Frankly, I don't even know where to tell you to begin improving it. I think you should just scrap what you have and rethink your approach. You are almost certainly better off just parsing all of the data into a single data structure and then producing your report afterwards.

    -sauoq
    "My two cents aren't worth a dime.";
    
      I agree it is horrible. But can you be so kind as to enlighten me on a better way of doing it.
        I think a HoH would make this problem a lot easier on the eye, so I offer a little example code, which does not print stuff out in the order you want, but hopefully gets you off in a slightly better direction:
        #!/usr/perl/bin use strict; my %printer_hash; my $current_printer; while(<DATA>) { if (/^printer/) { my ($idle, $enabled); ($current_printer,$idle,$enabled) = (split)[1,3,4]; $printer_hash{$current_printer}{IDLE_STATUS} = $idle eq "idle"?0:1 +; $printer_hash{$current_printer}{ENABLED} = $enabled eq "enable +d"?"UP":"DOWN"; } elsif ( /Interface:(.+)/i ) { chomp; $printer_hash{$current_printer}{INTERFACE} = (split /\//, $_)[ +-1]; } elsif ( /Description: (.+)/i) { $printer_hash{$current_printer}{INTERFACE} = $1; } elsif ( /Connection: (.+)/i) { $printer_hash{$current_printer}{CONNECTION} = $1 eq "direct"?"loca +l":"remote"; } elsif (/Banner not required/) { $printer_hash{$current_printer}{BANNER} = "NO"; } } foreach my $printer ( keys %printer_hash ){ foreach my $item ( keys %{$printer_hash{$printer}} ) { print "$printer => $item: $printer_hash{$printer}{$item}\n"; } } __DATA__ printer llp is idle. disnabled since Wed Oct 23 15:54:08 GMT 2002. ava +ilable. Form mounted: Content types: any Printer types: unknown Description: OPENprint printer llp Connection: direct Interface: /usr/lib/lp/model/standard On fault: write to root once After fault: continue Users allowed: (all) Forms allowed: (none) Banner not required Character sets: (none) Default pitch: Default page size: Default port settings: -opost printer ps is idle. enabled since Wed Oct 23 15:54:17 GMT 2002. availa +ble. Form mounted: Content types: postscript, simple Printer types: unknown Description: local printer Connection: direct Interface: /usr/lib/lp/model/net_lj4x On fault: write to root once After fault: continue Users allowed: (all) Forms allowed: (none) Banner not required Character sets: (none) Default pitch: Default page size: Default port settings:
        Note that I have not thoroughly checked it, but by printing out the items in the HoH, you can put them in any order you would like, and have a good idea what is getting printed when instead of having to re-read your code and try to remember which part of the array you are printing in what location, etc.

        -enlil

Re: Array insertion problem
by particle (Vicar) on Dec 11, 2002 at 03:05 UTC

    this should give you a running start. probably, you'll want to modify the %printer_info key to only include the values you want, and you'll want to display the keys in the order you want.

    #!/usr/bin/perl require 5.006; use strict; use warnings; $|++; my $infile = "t-printerstatus.input"; open( inputFH, "<", $infile ) or die "Can't open $infile for reading: $!\n"; my $logfile = "t-printerstatus.output"; open ( logFH, ">", $logfile ) or die "can't open $logfile for writing: $!\n"; my %printer_info = (); { ## set the input record separator to a double-newline local $/ = "\n\n"; while( my $record = <inputFH> ) { ## seperate the items in the record ## the first item is the key to the printer_info hash ## an item ends with a newline not followed by ## spaces and an open parenthesis my( $key, @item ) = split /(?x) \n (?! \s+ \( )/, $record; ## remove all leading whitespace from each item s/^\s*// for @item; ## split each item on a colon, ## add to the key in the printer_info hash for( @item ) { my( $name, $value ) = split /:\s+/, $_; @{ $printer_info{$key} }{$name} = $value; } } } use Data::Dumper; $Data::Dumper::Indent = 1; print Dumper \%printer_info;

    ~Particle *accelerates*

Re: Array insertion problem
by Enlil (Parson) on Dec 11, 2002 at 01:50 UTC
    The problem lies in this bit of code:
    if ($i == 3) { for ( sort { $a->[1] <=> $b->[1] } @array ) { print "$_->[0]|"; } @array=(); $i =0; } else { $i++; }
    Which is FWICT is counting lines, and when then sorting when $i==3 or every third line, and then printing the sorted array (which at the time contains ["llp", 1], ["Up", 5], [0, 6]), so the sorting works as expected. What you probably want is something along the following lines: Update:I agree with sauoq. I would think that storing all the data in a hash and then printing at the end would be a much better approach.

    -enlil

      Thanks